From e342e38df925973b86cd46d40bbe7f083414e2ad Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 8 Jun 2017 15:30:45 +0200 Subject: quota: Push dqio_sem down to ->read_dqblk() Push down acquisition of dqio_sem into ->read_dqblk() callback. It will allow quota formats to decide whether they need it or not. Reviewed-by: Andreas Dilger Signed-off-by: Jan Kara --- fs/quota/quota_v2.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'fs/quota/quota_v2.c') diff --git a/fs/quota/quota_v2.c b/fs/quota/quota_v2.c index ca71bf881ad1..b2cd34f6b3da 100644 --- a/fs/quota/quota_v2.c +++ b/fs/quota/quota_v2.c @@ -285,7 +285,15 @@ static int v2r1_is_id(void *dp, struct dquot *dquot) static int v2_read_dquot(struct dquot *dquot) { - return qtree_read_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv, dquot); + struct quota_info *dqopt = sb_dqopt(dquot->dq_sb); + int ret; + + down_read(&dqopt->dqio_sem); + ret = qtree_read_dquot( + sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv, + dquot); + up_read(&dqopt->dqio_sem); + return ret; } static int v2_write_dquot(struct dquot *dquot) -- cgit v1.2.3 From 8fc32c2b0db2c9ee0dffebea65bcdea03a29ba5a Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 8 Jun 2017 15:48:16 +0200 Subject: quota: Push dqio_sem down to ->write_dqblk() Push down acquisition of dqio_sem into ->write_dqblk() callback. It will allow quota formats to decide whether they need it or not. Reviewed-by: Andreas Dilger Signed-off-by: Jan Kara --- fs/quota/dquot.c | 11 ++++------- fs/quota/quota_v1.c | 3 +++ fs/quota/quota_v2.c | 10 +++++++++- 3 files changed, 16 insertions(+), 8 deletions(-) (limited to 'fs/quota/quota_v2.c') diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index 46046523abf0..562f5978488f 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c @@ -412,14 +412,14 @@ int dquot_acquire(struct dquot *dquot) set_bit(DQ_READ_B, &dquot->dq_flags); /* Instantiate dquot if needed */ if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags) && !dquot->dq_off) { - down_write(&dqopt->dqio_sem); ret = dqopt->ops[dquot->dq_id.type]->commit_dqblk(dquot); /* Write the info if needed */ if (info_dirty(&dqopt->info[dquot->dq_id.type])) { + down_write(&dqopt->dqio_sem); ret2 = dqopt->ops[dquot->dq_id.type]->write_file_info( dquot->dq_sb, dquot->dq_id.type); + up_write(&dqopt->dqio_sem); } - up_write(&dqopt->dqio_sem); if (ret < 0) goto out_iolock; if (ret2 < 0) { @@ -456,13 +456,10 @@ int dquot_commit(struct dquot *dquot) spin_unlock(&dq_list_lock); /* Inactive dquot can be only if there was error during read/init * => we have better not writing it */ - if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) { - down_write(&dqopt->dqio_sem); + if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) ret = dqopt->ops[dquot->dq_id.type]->commit_dqblk(dquot); - up_write(&dqopt->dqio_sem); - } else { + else ret = -EIO; - } out_lock: mutex_unlock(&dquot->dq_lock); return ret; diff --git a/fs/quota/quota_v1.c b/fs/quota/quota_v1.c index 12d69cda57cc..94cceb76b9a3 100644 --- a/fs/quota/quota_v1.c +++ b/fs/quota/quota_v1.c @@ -83,7 +83,9 @@ static int v1_commit_dqblk(struct dquot *dquot) short type = dquot->dq_id.type; ssize_t ret; struct v1_disk_dqblk dqblk; + struct quota_info *dqopt = sb_dqopt(dquot->dq_sb); + down_write(&dqopt->dqio_sem); v1_mem2disk_dqblk(&dqblk, &dquot->dq_dqb); if (((type == USRQUOTA) && uid_eq(dquot->dq_id.uid, GLOBAL_ROOT_UID)) || ((type == GRPQUOTA) && gid_eq(dquot->dq_id.gid, GLOBAL_ROOT_GID))) { @@ -97,6 +99,7 @@ static int v1_commit_dqblk(struct dquot *dquot) ret = dquot->dq_sb->s_op->quota_write(dquot->dq_sb, type, (char *)&dqblk, sizeof(struct v1_disk_dqblk), v1_dqoff(from_kqid(&init_user_ns, dquot->dq_id))); + up_write(&dqopt->dqio_sem); if (ret != sizeof(struct v1_disk_dqblk)) { quota_error(dquot->dq_sb, "dquota write failed"); if (ret >= 0) diff --git a/fs/quota/quota_v2.c b/fs/quota/quota_v2.c index b2cd34f6b3da..482733abe4ac 100644 --- a/fs/quota/quota_v2.c +++ b/fs/quota/quota_v2.c @@ -298,7 +298,15 @@ static int v2_read_dquot(struct dquot *dquot) static int v2_write_dquot(struct dquot *dquot) { - return qtree_write_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv, dquot); + struct quota_info *dqopt = sb_dqopt(dquot->dq_sb); + int ret; + + down_write(&dqopt->dqio_sem); + ret = qtree_write_dquot( + sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv, + dquot); + up_write(&dqopt->dqio_sem); + return ret; } static int v2_release_dquot(struct dquot *dquot) -- cgit v1.2.3 From d2faa415166b2883428efa92f451774ef44373ac Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 8 Jun 2017 16:09:46 +0200 Subject: quota: Do not acquire dqio_sem for dquot overwrites in v2 format When dquot has space already allocated in a quota file, we just overwrite that place when writing dquot. So we don't need any protection against other modifications of quota file as these keep dquot in place. Reviewed-by: Andreas Dilger Signed-off-by: Jan Kara --- fs/quota/quota_v2.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'fs/quota/quota_v2.c') diff --git a/fs/quota/quota_v2.c b/fs/quota/quota_v2.c index 482733abe4ac..7a05b80f3b8c 100644 --- a/fs/quota/quota_v2.c +++ b/fs/quota/quota_v2.c @@ -300,12 +300,23 @@ static int v2_write_dquot(struct dquot *dquot) { struct quota_info *dqopt = sb_dqopt(dquot->dq_sb); int ret; - - down_write(&dqopt->dqio_sem); + bool alloc = false; + + /* + * If space for dquot is already allocated, we don't need any + * protection as we'll only overwrite the place of dquot. We are + * still protected by concurrent writes of the same dquot by + * dquot->dq_lock. + */ + if (!dquot->dq_off) { + alloc = true; + down_write(&dqopt->dqio_sem); + } ret = qtree_write_dquot( sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv, dquot); - up_write(&dqopt->dqio_sem); + if (alloc) + up_write(&dqopt->dqio_sem); return ret; } -- cgit v1.2.3 From b9a1a7f4b6b5861c6ae89a125271103ceb8c8690 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 8 Jun 2017 17:20:36 +0200 Subject: quota: Push dqio_sem down to ->release_dqblk() Push down acquisition of dqio_sem into ->release_dqblk() callback. It will allow quota formats to decide whether they need it or not. Reviewed-by: Andreas Dilger Signed-off-by: Jan Kara --- fs/quota/dquot.c | 4 ++-- fs/quota/quota_v2.c | 9 ++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) (limited to 'fs/quota/quota_v2.c') diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index 562f5978488f..3b3c7f094ff8 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c @@ -478,19 +478,19 @@ int dquot_release(struct dquot *dquot) /* Check whether we are not racing with some other dqget() */ if (atomic_read(&dquot->dq_count) > 1) goto out_dqlock; - down_write(&dqopt->dqio_sem); if (dqopt->ops[dquot->dq_id.type]->release_dqblk) { ret = dqopt->ops[dquot->dq_id.type]->release_dqblk(dquot); /* Write the info */ if (info_dirty(&dqopt->info[dquot->dq_id.type])) { + down_write(&dqopt->dqio_sem); ret2 = dqopt->ops[dquot->dq_id.type]->write_file_info( dquot->dq_sb, dquot->dq_id.type); + up_write(&dqopt->dqio_sem); } if (ret >= 0) ret = ret2; } clear_bit(DQ_ACTIVE_B, &dquot->dq_flags); - up_write(&dqopt->dqio_sem); out_dqlock: mutex_unlock(&dquot->dq_lock); return ret; diff --git a/fs/quota/quota_v2.c b/fs/quota/quota_v2.c index 7a05b80f3b8c..8f54b159e423 100644 --- a/fs/quota/quota_v2.c +++ b/fs/quota/quota_v2.c @@ -322,7 +322,14 @@ static int v2_write_dquot(struct dquot *dquot) static int v2_release_dquot(struct dquot *dquot) { - return qtree_release_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv, dquot); + struct quota_info *dqopt = sb_dqopt(dquot->dq_sb); + int ret; + + down_write(&dqopt->dqio_sem); + ret = qtree_release_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv, dquot); + up_write(&dqopt->dqio_sem); + + return ret; } static int v2_free_file_info(struct super_block *sb, int type) -- cgit v1.2.3 From f14618c6823ee0f9f92a87aad7d5ad26916ccff1 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Fri, 9 Jun 2017 08:36:16 +0200 Subject: quota: Push dqio_sem down to ->get_next_id() Push down acquisition of dqio_sem into ->get_next_id() callback. Mostly for consistency with other operations. Reviewed-by: Andreas Dilger Signed-off-by: Jan Kara --- fs/quota/dquot.c | 6 +----- fs/quota/quota_v2.c | 8 +++++++- 2 files changed, 8 insertions(+), 6 deletions(-) (limited to 'fs/quota/quota_v2.c') diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index 3b3c7f094ff8..332f7026edad 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c @@ -2067,16 +2067,12 @@ EXPORT_SYMBOL(dquot_commit_info); int dquot_get_next_id(struct super_block *sb, struct kqid *qid) { struct quota_info *dqopt = sb_dqopt(sb); - int err; if (!sb_has_quota_active(sb, qid->type)) return -ESRCH; if (!dqopt->ops[qid->type]->get_next_id) return -ENOSYS; - down_read(&dqopt->dqio_sem); - err = dqopt->ops[qid->type]->get_next_id(sb, qid); - up_read(&dqopt->dqio_sem); - return err; + return dqopt->ops[qid->type]->get_next_id(sb, qid); } EXPORT_SYMBOL(dquot_get_next_id); diff --git a/fs/quota/quota_v2.c b/fs/quota/quota_v2.c index 8f54b159e423..f82638e43c07 100644 --- a/fs/quota/quota_v2.c +++ b/fs/quota/quota_v2.c @@ -340,7 +340,13 @@ static int v2_free_file_info(struct super_block *sb, int type) static int v2_get_next_id(struct super_block *sb, struct kqid *qid) { - return qtree_get_next_id(sb_dqinfo(sb, qid->type)->dqi_priv, qid); + struct quota_info *dqopt = sb_dqopt(sb); + int ret; + + down_read(&dqopt->dqio_sem); + ret = qtree_get_next_id(sb_dqinfo(sb, qid->type)->dqi_priv, qid); + up_read(&dqopt->dqio_sem); + return ret; } static const struct quota_format_ops v2_format_ops = { -- cgit v1.2.3 From 9a8ae30e73cb8827dd0a8ae5fd505db457cfb7ed Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Fri, 9 Jun 2017 08:45:43 +0200 Subject: quota: Push dqio_sem down to ->write_file_info() Push down acquisition of dqio_sem into ->write_file_info() callback. Mostly for consistency with other operations. Reviewed-by: Andreas Dilger Signed-off-by: Jan Kara --- fs/ocfs2/quota_global.c | 8 ++++++-- fs/quota/dquot.c | 10 +--------- fs/quota/quota_v1.c | 2 ++ fs/quota/quota_v2.c | 5 ++++- 4 files changed, 13 insertions(+), 12 deletions(-) (limited to 'fs/quota/quota_v2.c') diff --git a/fs/ocfs2/quota_global.c b/fs/ocfs2/quota_global.c index 4134d557a8e5..78f3a869748c 100644 --- a/fs/ocfs2/quota_global.c +++ b/fs/ocfs2/quota_global.c @@ -443,13 +443,17 @@ static int __ocfs2_global_write_info(struct super_block *sb, int type) int ocfs2_global_write_info(struct super_block *sb, int type) { int err; - struct ocfs2_mem_dqinfo *info = sb_dqinfo(sb, type)->dqi_priv; + struct quota_info *dqopt = sb_dqopt(sb); + struct ocfs2_mem_dqinfo *info = dqopt->info[type].dqi_priv; + down_write(&dqopt->dqio_sem); err = ocfs2_qinfo_lock(info, 1); if (err < 0) - return err; + goto out_sem; err = __ocfs2_global_write_info(sb, type); ocfs2_qinfo_unlock(info, 1); +out_sem: + up_write(&dqopt->dqio_sem); return err; } diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index 332f7026edad..1e1ff97098ec 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c @@ -415,10 +415,8 @@ int dquot_acquire(struct dquot *dquot) ret = dqopt->ops[dquot->dq_id.type]->commit_dqblk(dquot); /* Write the info if needed */ if (info_dirty(&dqopt->info[dquot->dq_id.type])) { - down_write(&dqopt->dqio_sem); ret2 = dqopt->ops[dquot->dq_id.type]->write_file_info( dquot->dq_sb, dquot->dq_id.type); - up_write(&dqopt->dqio_sem); } if (ret < 0) goto out_iolock; @@ -482,10 +480,8 @@ int dquot_release(struct dquot *dquot) ret = dqopt->ops[dquot->dq_id.type]->release_dqblk(dquot); /* Write the info */ if (info_dirty(&dqopt->info[dquot->dq_id.type])) { - down_write(&dqopt->dqio_sem); ret2 = dqopt->ops[dquot->dq_id.type]->write_file_info( dquot->dq_sb, dquot->dq_id.type); - up_write(&dqopt->dqio_sem); } if (ret >= 0) ret = ret2; @@ -2054,13 +2050,9 @@ EXPORT_SYMBOL(dquot_transfer); */ int dquot_commit_info(struct super_block *sb, int type) { - int ret; struct quota_info *dqopt = sb_dqopt(sb); - down_write(&dqopt->dqio_sem); - ret = dqopt->ops[type]->write_file_info(sb, type); - up_write(&dqopt->dqio_sem); - return ret; + return dqopt->ops[type]->write_file_info(sb, type); } EXPORT_SYMBOL(dquot_commit_info); diff --git a/fs/quota/quota_v1.c b/fs/quota/quota_v1.c index 12d69cda57cc..fe68bf544b29 100644 --- a/fs/quota/quota_v1.c +++ b/fs/quota/quota_v1.c @@ -186,6 +186,7 @@ static int v1_write_file_info(struct super_block *sb, int type) struct v1_disk_dqblk dqblk; int ret; + down_write(&dqopt->dqio_sem); dqopt->info[type].dqi_flags &= ~DQF_INFO_DIRTY; ret = sb->s_op->quota_read(sb, type, (char *)&dqblk, sizeof(struct v1_disk_dqblk), v1_dqoff(0)); @@ -203,6 +204,7 @@ static int v1_write_file_info(struct super_block *sb, int type) else if (ret > 0) ret = -EIO; out: + up_write(&dqopt->dqio_sem); return ret; } diff --git a/fs/quota/quota_v2.c b/fs/quota/quota_v2.c index f82638e43c07..5e47012d2f57 100644 --- a/fs/quota/quota_v2.c +++ b/fs/quota/quota_v2.c @@ -154,10 +154,12 @@ static int v2_read_file_info(struct super_block *sb, int type) static int v2_write_file_info(struct super_block *sb, int type) { struct v2_disk_dqinfo dinfo; - struct mem_dqinfo *info = sb_dqinfo(sb, type); + struct quota_info *dqopt = sb_dqopt(sb); + struct mem_dqinfo *info = &dqopt->info[type]; struct qtree_mem_dqinfo *qinfo = info->dqi_priv; ssize_t size; + down_write(&dqopt->dqio_sem); spin_lock(&dq_data_lock); info->dqi_flags &= ~DQF_INFO_DIRTY; dinfo.dqi_bgrace = cpu_to_le32(info->dqi_bgrace); @@ -170,6 +172,7 @@ static int v2_write_file_info(struct super_block *sb, int type) dinfo.dqi_free_entry = cpu_to_le32(qinfo->dqi_free_entry); size = sb->s_op->quota_write(sb, type, (char *)&dinfo, sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF); + up_write(&dqopt->dqio_sem); if (size != sizeof(struct v2_disk_dqinfo)) { quota_error(sb, "Can't write info structure"); return -1; -- cgit v1.2.3 From 42fdb8583d5a7eaf916c7323fce6cb4728f364c4 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Fri, 9 Jun 2017 08:59:46 +0200 Subject: quota: Push dqio_sem down to ->read_file_info() Push down acquisition of dqio_sem into ->read_file_info() callback. This is for consistency with other operations and it also allows us to get rid of an ugliness in OCFS2. Reviewed-by: Andreas Dilger Signed-off-by: Jan Kara --- fs/ocfs2/quota_local.c | 5 ----- fs/quota/dquot.c | 6 +----- fs/quota/quota_v1.c | 2 ++ fs/quota/quota_v2.c | 28 ++++++++++++++++++++-------- 4 files changed, 23 insertions(+), 18 deletions(-) (limited to 'fs/quota/quota_v2.c') diff --git a/fs/ocfs2/quota_local.c b/fs/ocfs2/quota_local.c index 1829f6a45d46..2eeedcc2e9da 100644 --- a/fs/ocfs2/quota_local.c +++ b/fs/ocfs2/quota_local.c @@ -691,9 +691,6 @@ static int ocfs2_local_read_info(struct super_block *sb, int type) struct ocfs2_quota_recovery *rec; int locked = 0; - /* We don't need the lock and we have to acquire quota file locks - * which will later depend on this lock */ - up_read(&sb_dqopt(sb)->dqio_sem); info->dqi_max_spc_limit = 0x7fffffffffffffffLL; info->dqi_max_ino_limit = 0x7fffffffffffffffLL; oinfo = kmalloc(sizeof(struct ocfs2_mem_dqinfo), GFP_NOFS); @@ -772,7 +769,6 @@ static int ocfs2_local_read_info(struct super_block *sb, int type) goto out_err; } - down_read(&sb_dqopt(sb)->dqio_sem); return 0; out_err: if (oinfo) { @@ -786,7 +782,6 @@ out_err: kfree(oinfo); } brelse(bh); - down_read(&sb_dqopt(sb)->dqio_sem); return -1; } diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index 1e1ff97098ec..5e77c4da69a6 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c @@ -2313,15 +2313,11 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id, dqopt->info[type].dqi_format = fmt; dqopt->info[type].dqi_fmt_id = format_id; INIT_LIST_HEAD(&dqopt->info[type].dqi_dirty_list); - down_read(&dqopt->dqio_sem); error = dqopt->ops[type]->read_file_info(sb, type); - if (error < 0) { - up_read(&dqopt->dqio_sem); + if (error < 0) goto out_file_init; - } if (dqopt->flags & DQUOT_QUOTA_SYS_FILE) dqopt->info[type].dqi_flags |= DQF_SYS_FILE; - up_read(&dqopt->dqio_sem); spin_lock(&dq_state_lock); dqopt->flags |= dquot_state_flag(flags, type); spin_unlock(&dq_state_lock); diff --git a/fs/quota/quota_v1.c b/fs/quota/quota_v1.c index fe68bf544b29..b2d8e04e567a 100644 --- a/fs/quota/quota_v1.c +++ b/fs/quota/quota_v1.c @@ -161,6 +161,7 @@ static int v1_read_file_info(struct super_block *sb, int type) struct v1_disk_dqblk dqblk; int ret; + down_read(&dqopt->dqio_sem); ret = sb->s_op->quota_read(sb, type, (char *)&dqblk, sizeof(struct v1_disk_dqblk), v1_dqoff(0)); if (ret != sizeof(struct v1_disk_dqblk)) { @@ -177,6 +178,7 @@ static int v1_read_file_info(struct super_block *sb, int type) dqopt->info[type].dqi_bgrace = dqblk.dqb_btime ? dqblk.dqb_btime : MAX_DQ_TIME; out: + up_read(&dqopt->dqio_sem); return ret; } diff --git a/fs/quota/quota_v2.c b/fs/quota/quota_v2.c index 5e47012d2f57..373d7cfea5b0 100644 --- a/fs/quota/quota_v2.c +++ b/fs/quota/quota_v2.c @@ -90,29 +90,38 @@ static int v2_read_file_info(struct super_block *sb, int type) { struct v2_disk_dqinfo dinfo; struct v2_disk_dqheader dqhead; - struct mem_dqinfo *info = sb_dqinfo(sb, type); + struct quota_info *dqopt = sb_dqopt(sb); + struct mem_dqinfo *info = &dqopt->info[type]; struct qtree_mem_dqinfo *qinfo; ssize_t size; unsigned int version; + int ret; - if (!v2_read_header(sb, type, &dqhead)) - return -1; + down_read(&dqopt->dqio_sem); + if (!v2_read_header(sb, type, &dqhead)) { + ret = -1; + goto out; + } version = le32_to_cpu(dqhead.dqh_version); if ((info->dqi_fmt_id == QFMT_VFS_V0 && version != 0) || - (info->dqi_fmt_id == QFMT_VFS_V1 && version != 1)) - return -1; + (info->dqi_fmt_id == QFMT_VFS_V1 && version != 1)) { + ret = -1; + goto out; + } size = sb->s_op->quota_read(sb, type, (char *)&dinfo, sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF); if (size != sizeof(struct v2_disk_dqinfo)) { quota_error(sb, "Can't read info structure"); - return -1; + ret = -1; + goto out; } info->dqi_priv = kmalloc(sizeof(struct qtree_mem_dqinfo), GFP_NOFS); if (!info->dqi_priv) { printk(KERN_WARNING "Not enough memory for quota information structure.\n"); - return -ENOMEM; + ret = -ENOMEM; + goto out; } qinfo = info->dqi_priv; if (version == 0) { @@ -147,7 +156,10 @@ static int v2_read_file_info(struct super_block *sb, int type) qinfo->dqi_entry_size = sizeof(struct v2r1_disk_dqblk); qinfo->dqi_ops = &v2r1_qtree_ops; } - return 0; + ret = 0; +out: + up_read(&dqopt->dqio_sem); + return ret; } /* Write information header to quota file */ -- cgit v1.2.3 From cb8d01b4f624bbf34fd82cbca19e34a22d1eeef6 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Fri, 9 Jun 2017 09:04:47 +0200 Subject: quota: Fix error codes in v2_read_file_info() v2_read_file_info() returned -1 instead of proper error codes on error. Luckily this is not easily visible from userspace as we have called ->check_quota_file shortly before and thus already verified the quota file is sane. Still set the error codes to proper values. Reviewed-by: Andreas Dilger Signed-off-by: Jan Kara --- fs/quota/quota_v2.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'fs/quota/quota_v2.c') diff --git a/fs/quota/quota_v2.c b/fs/quota/quota_v2.c index 373d7cfea5b0..21a8bdf7cfec 100644 --- a/fs/quota/quota_v2.c +++ b/fs/quota/quota_v2.c @@ -99,13 +99,13 @@ static int v2_read_file_info(struct super_block *sb, int type) down_read(&dqopt->dqio_sem); if (!v2_read_header(sb, type, &dqhead)) { - ret = -1; + ret = -EIO; goto out; } version = le32_to_cpu(dqhead.dqh_version); if ((info->dqi_fmt_id == QFMT_VFS_V0 && version != 0) || (info->dqi_fmt_id == QFMT_VFS_V1 && version != 1)) { - ret = -1; + ret = -EINVAL; goto out; } @@ -113,7 +113,7 @@ static int v2_read_file_info(struct super_block *sb, int type) sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF); if (size != sizeof(struct v2_disk_dqinfo)) { quota_error(sb, "Can't read info structure"); - ret = -1; + ret = -EIO; goto out; } info->dqi_priv = kmalloc(sizeof(struct qtree_mem_dqinfo), GFP_NOFS); -- cgit v1.2.3 From f98bbe37ae96873ce93f36f4cdc7b47d85cc4455 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 17 Aug 2017 19:20:28 +0200 Subject: quota: Propagate ->quota_read errors from v2_read_file_info() Currently we return -EIO on any error (or short read) from ->quota_read() while reading quota info. Propagate the error code instead. Suggested-by: Andreas Dilger Signed-off-by: Jan Kara --- fs/quota/quota_v2.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'fs/quota/quota_v2.c') diff --git a/fs/quota/quota_v2.c b/fs/quota/quota_v2.c index 21a8bdf7cfec..cdbf71664cdc 100644 --- a/fs/quota/quota_v2.c +++ b/fs/quota/quota_v2.c @@ -65,9 +65,11 @@ static int v2_read_header(struct super_block *sb, int type, if (size != sizeof(struct v2_disk_dqheader)) { quota_error(sb, "Failed header read: expected=%zd got=%zd", sizeof(struct v2_disk_dqheader), size); - return 0; + if (size < 0) + return size; + return -EIO; } - return 1; + return 0; } /* Check whether given file is really vfsv0 quotafile */ @@ -77,7 +79,7 @@ static int v2_check_quota_file(struct super_block *sb, int type) static const uint quota_magics[] = V2_INITQMAGICS; static const uint quota_versions[] = V2_INITQVERSIONS; - if (!v2_read_header(sb, type, &dqhead)) + if (v2_read_header(sb, type, &dqhead)) return 0; if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type] || le32_to_cpu(dqhead.dqh_version) > quota_versions[type]) @@ -98,10 +100,9 @@ static int v2_read_file_info(struct super_block *sb, int type) int ret; down_read(&dqopt->dqio_sem); - if (!v2_read_header(sb, type, &dqhead)) { - ret = -EIO; + ret = v2_read_header(sb, type, &dqhead); + if (ret < 0) goto out; - } version = le32_to_cpu(dqhead.dqh_version); if ((info->dqi_fmt_id == QFMT_VFS_V0 && version != 0) || (info->dqi_fmt_id == QFMT_VFS_V1 && version != 1)) { @@ -113,7 +114,10 @@ static int v2_read_file_info(struct super_block *sb, int type) sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF); if (size != sizeof(struct v2_disk_dqinfo)) { quota_error(sb, "Can't read info structure"); - ret = -EIO; + if (size < 0) + ret = size; + else + ret = -EIO; goto out; } info->dqi_priv = kmalloc(sizeof(struct qtree_mem_dqinfo), GFP_NOFS); -- cgit v1.2.3