quota: Set nofs allocation context when acquiring dqio_sem
authorJan Kara <jack@suse.cz>
Mon, 22 Jan 2024 12:31:21 +0000 (13:31 +0100)
committerJan Kara <jack@suse.cz>
Tue, 23 Jan 2024 18:21:11 +0000 (19:21 +0100)
dqio_sem can be acquired during inode reclaim through dquot_drop() ->
dqput() -> dquot_release() -> write_file_info() context. In some cases
(most notably through dquot_get_next_id()) it can be acquired without
holding dquot->dq_lock (which already sets nofs allocation context). So
we need to set nofs allocation context when acquiring it as well.

Signed-off-by: Jan Kara <jack@suse.cz>
fs/ocfs2/quota_global.c
fs/ocfs2/quota_local.c
fs/quota/quota_v1.c
fs/quota/quota_v2.c

index dc9f76a..0575c2d 100644 (file)
@@ -447,14 +447,17 @@ int ocfs2_global_write_info(struct super_block *sb, int type)
        int err;
        struct quota_info *dqopt = sb_dqopt(sb);
        struct ocfs2_mem_dqinfo *info = dqopt->info[type].dqi_priv;
+       unsigned int memalloc;
 
        down_write(&dqopt->dqio_sem);
+       memalloc = memalloc_nofs_save();
        err = ocfs2_qinfo_lock(info, 1);
        if (err < 0)
                goto out_sem;
        err = __ocfs2_global_write_info(sb, type);
        ocfs2_qinfo_unlock(info, 1);
 out_sem:
+       memalloc_nofs_restore(memalloc);
        up_write(&dqopt->dqio_sem);
        return err;
 }
@@ -601,6 +604,7 @@ static int ocfs2_sync_dquot_helper(struct dquot *dquot, unsigned long type)
        struct ocfs2_mem_dqinfo *oinfo = sb_dqinfo(sb, type)->dqi_priv;
        struct ocfs2_super *osb = OCFS2_SB(sb);
        int status = 0;
+       unsigned int memalloc;
 
        trace_ocfs2_sync_dquot_helper(from_kqid(&init_user_ns, dquot->dq_id),
                                      dquot->dq_id.type,
@@ -618,6 +622,7 @@ static int ocfs2_sync_dquot_helper(struct dquot *dquot, unsigned long type)
                goto out_ilock;
        }
        down_write(&sb_dqopt(sb)->dqio_sem);
+       memalloc = memalloc_nofs_save();
        status = ocfs2_sync_dquot(dquot);
        if (status < 0)
                mlog_errno(status);
@@ -625,6 +630,7 @@ static int ocfs2_sync_dquot_helper(struct dquot *dquot, unsigned long type)
        status = ocfs2_local_write_dquot(dquot);
        if (status < 0)
                mlog_errno(status);
+       memalloc_nofs_restore(memalloc);
        up_write(&sb_dqopt(sb)->dqio_sem);
        ocfs2_commit_trans(osb, handle);
 out_ilock:
@@ -662,6 +668,7 @@ static int ocfs2_write_dquot(struct dquot *dquot)
        handle_t *handle;
        struct ocfs2_super *osb = OCFS2_SB(dquot->dq_sb);
        int status = 0;
+       unsigned int memalloc;
 
        trace_ocfs2_write_dquot(from_kqid(&init_user_ns, dquot->dq_id),
                                dquot->dq_id.type);
@@ -673,7 +680,9 @@ static int ocfs2_write_dquot(struct dquot *dquot)
                goto out;
        }
        down_write(&sb_dqopt(dquot->dq_sb)->dqio_sem);
+       memalloc = memalloc_nofs_save();
        status = ocfs2_local_write_dquot(dquot);
+       memalloc_nofs_restore(memalloc);
        up_write(&sb_dqopt(dquot->dq_sb)->dqio_sem);
        ocfs2_commit_trans(osb, handle);
 out:
@@ -920,6 +929,7 @@ static int ocfs2_mark_dquot_dirty(struct dquot *dquot)
        struct ocfs2_mem_dqinfo *oinfo = sb_dqinfo(sb, type)->dqi_priv;
        handle_t *handle;
        struct ocfs2_super *osb = OCFS2_SB(sb);
+       unsigned int memalloc;
 
        trace_ocfs2_mark_dquot_dirty(from_kqid(&init_user_ns, dquot->dq_id),
                                     type);
@@ -946,6 +956,7 @@ static int ocfs2_mark_dquot_dirty(struct dquot *dquot)
                goto out_ilock;
        }
        down_write(&sb_dqopt(sb)->dqio_sem);
+       memalloc = memalloc_nofs_save();
        status = ocfs2_sync_dquot(dquot);
        if (status < 0) {
                mlog_errno(status);
@@ -954,6 +965,7 @@ static int ocfs2_mark_dquot_dirty(struct dquot *dquot)
        /* Now write updated local dquot structure */
        status = ocfs2_local_write_dquot(dquot);
 out_dlock:
+       memalloc_nofs_restore(memalloc);
        up_write(&sb_dqopt(sb)->dqio_sem);
        ocfs2_commit_trans(osb, handle);
 out_ilock:
index e09842f..8ce462c 100644 (file)
@@ -470,6 +470,7 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode,
        int bit, chunk;
        struct ocfs2_recovery_chunk *rchunk, *next;
        qsize_t spacechange, inodechange;
+       unsigned int memalloc;
 
        trace_ocfs2_recover_local_quota_file((unsigned long)lqinode->i_ino, type);
 
@@ -521,6 +522,7 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode,
                                goto out_drop_lock;
                        }
                        down_write(&sb_dqopt(sb)->dqio_sem);
+                       memalloc = memalloc_nofs_save();
                        spin_lock(&dquot->dq_dqb_lock);
                        /* Add usage from quota entry into quota changes
                         * of our node. Auxiliary variables are important
@@ -553,6 +555,7 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode,
                        unlock_buffer(qbh);
                        ocfs2_journal_dirty(handle, qbh);
 out_commit:
+                       memalloc_nofs_restore(memalloc);
                        up_write(&sb_dqopt(sb)->dqio_sem);
                        ocfs2_commit_trans(OCFS2_SB(sb), handle);
 out_drop_lock:
index a0db3f1..3f3e8ac 100644 (file)
@@ -160,9 +160,11 @@ static int v1_read_file_info(struct super_block *sb, int type)
 {
        struct quota_info *dqopt = sb_dqopt(sb);
        struct v1_disk_dqblk dqblk;
+       unsigned int memalloc;
        int ret;
 
        down_read(&dqopt->dqio_sem);
+       memalloc = memalloc_nofs_save();
        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)) {
@@ -179,6 +181,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:
+       memalloc_nofs_restore(memalloc);
        up_read(&dqopt->dqio_sem);
        return ret;
 }
@@ -187,9 +190,11 @@ static int v1_write_file_info(struct super_block *sb, int type)
 {
        struct quota_info *dqopt = sb_dqopt(sb);
        struct v1_disk_dqblk dqblk;
+       unsigned int memalloc;
        int ret;
 
        down_write(&dqopt->dqio_sem);
+       memalloc = memalloc_nofs_save();
        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)) {
@@ -209,6 +214,7 @@ static int v1_write_file_info(struct super_block *sb, int type)
        else if (ret >= 0)
                ret = -EIO;
 out:
+       memalloc_nofs_restore(memalloc);
        up_write(&dqopt->dqio_sem);
        return ret;
 }
index ae99e7b..48e0d61 100644 (file)
@@ -96,9 +96,11 @@ static int v2_read_file_info(struct super_block *sb, int type)
        struct qtree_mem_dqinfo *qinfo;
        ssize_t size;
        unsigned int version;
+       unsigned int memalloc;
        int ret;
 
        down_read(&dqopt->dqio_sem);
+       memalloc = memalloc_nofs_save();
        ret = v2_read_header(sb, type, &dqhead);
        if (ret < 0)
                goto out;
@@ -183,6 +185,7 @@ out_free:
                info->dqi_priv = NULL;
        }
 out:
+       memalloc_nofs_restore(memalloc);
        up_read(&dqopt->dqio_sem);
        return ret;
 }
@@ -195,8 +198,10 @@ static int v2_write_file_info(struct super_block *sb, int type)
        struct mem_dqinfo *info = &dqopt->info[type];
        struct qtree_mem_dqinfo *qinfo = info->dqi_priv;
        ssize_t size;
+       unsigned int memalloc;
 
        down_write(&dqopt->dqio_sem);
+       memalloc = memalloc_nofs_save();
        spin_lock(&dq_data_lock);
        info->dqi_flags &= ~DQF_INFO_DIRTY;
        dinfo.dqi_bgrace = cpu_to_le32(info->dqi_bgrace);
@@ -209,6 +214,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);
+       memalloc_nofs_restore(memalloc);
        up_write(&dqopt->dqio_sem);
        if (size != sizeof(struct v2_disk_dqinfo)) {
                quota_error(sb, "Can't write info structure");
@@ -328,11 +334,14 @@ static int v2_read_dquot(struct dquot *dquot)
 {
        struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
        int ret;
+       unsigned int memalloc;
 
        down_read(&dqopt->dqio_sem);
+       memalloc = memalloc_nofs_save();
        ret = qtree_read_dquot(
                        sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv,
                        dquot);
+       memalloc_nofs_restore(memalloc);
        up_read(&dqopt->dqio_sem);
        return ret;
 }
@@ -342,6 +351,7 @@ static int v2_write_dquot(struct dquot *dquot)
        struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
        int ret;
        bool alloc = false;
+       unsigned int memalloc;
 
        /*
         * If space for dquot is already allocated, we don't need any
@@ -355,9 +365,11 @@ static int v2_write_dquot(struct dquot *dquot)
        } else {
                down_read(&dqopt->dqio_sem);
        }
+       memalloc = memalloc_nofs_save();
        ret = qtree_write_dquot(
                        sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv,
                        dquot);
+       memalloc_nofs_restore(memalloc);
        if (alloc)
                up_write(&dqopt->dqio_sem);
        else
@@ -368,10 +380,13 @@ static int v2_write_dquot(struct dquot *dquot)
 static int v2_release_dquot(struct dquot *dquot)
 {
        struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
+       unsigned int memalloc;
        int ret;
 
        down_write(&dqopt->dqio_sem);
+       memalloc = memalloc_nofs_save();
        ret = qtree_release_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv, dquot);
+       memalloc_nofs_restore(memalloc);
        up_write(&dqopt->dqio_sem);
 
        return ret;
@@ -386,10 +401,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)
 {
        struct quota_info *dqopt = sb_dqopt(sb);
+       unsigned int memalloc;
        int ret;
 
        down_read(&dqopt->dqio_sem);
+       memalloc = memalloc_nofs_save();
        ret = qtree_get_next_id(sb_dqinfo(sb, qid->type)->dqi_priv, qid);
+       memalloc_nofs_restore(memalloc);
        up_read(&dqopt->dqio_sem);
        return ret;
 }