Skip to content

Commit c2db5c5

Browse files
Hakon-BuggeNipaLocal
authored andcommitted
workqueue: Inherit NOIO and NOFS alloc flags
For drivers/modules running inside a memalloc_{noio,nofs}_{save,restore} region, if a work-queue is created, we make sure work executed on the work-queue inherits the same flag(s). This in order to conditionally enable drivers to work aligned with block I/O devices. This commit makes sure that any work queued later on work-queues created during module initialization, when current's flags has PF_MEMALLOC_{NOIO,NOFS} set, will inherit the same flags. We do this in order to enable drivers to be used as a network block I/O device. This in order to support XFS or other file-systems on top of a raw block device which uses said drivers as the network transport layer. Under intense memory pressure, we get memory reclaims. Assume the file-system reclaims memory, goes to the raw block device, which calls into said drivers. Now, if regular GFP_KERNEL allocations in the drivers require reclaims to be fulfilled, we end up in a circular dependency. We break this circular dependency by: 1. Force all allocations in the drivers to use GFP_NOIO, by means of a parenthetic use of memalloc_noio_{save,restore} on all relevant entry points. 2. Make sure work-queues inherits current->flags wrt. PF_MEMALLOC_{NOIO,NOFS}, such that work executed on the work-queue inherits the same flag(s). That is what this commit contributes with. Signed-off-by: Håkon Bugge <[email protected]> Signed-off-by: NipaLocal <nipa@local>
1 parent 91893f4 commit c2db5c5

File tree

2 files changed

+23
-0
lines changed

2 files changed

+23
-0
lines changed

include/linux/workqueue.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,8 @@ enum wq_flags {
398398
__WQ_DRAINING = 1 << 16, /* internal: workqueue is draining */
399399
__WQ_ORDERED = 1 << 17, /* internal: workqueue is ordered */
400400
__WQ_LEGACY = 1 << 18, /* internal: create*_workqueue() */
401+
__WQ_NOIO = 1 << 19, /* internal: execute work with NOIO */
402+
__WQ_NOFS = 1 << 20, /* internal: execute work with NOFS */
401403

402404
/* BH wq only allows the following flags */
403405
__WQ_BH_ALLOWS = WQ_BH | WQ_HIGHPRI,

kernel/workqueue.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
#include <linux/uaccess.h>
5252
#include <linux/sched/isolation.h>
5353
#include <linux/sched/debug.h>
54+
#include <linux/sched/mm.h>
5455
#include <linux/nmi.h>
5556
#include <linux/kvm_para.h>
5657
#include <linux/delay.h>
@@ -3172,6 +3173,10 @@ __acquires(&pool->lock)
31723173
unsigned long work_data;
31733174
int lockdep_start_depth, rcu_start_depth;
31743175
bool bh_draining = pool->flags & POOL_BH_DRAINING;
3176+
bool use_noio_allocs = pwq->wq->flags & __WQ_NOIO;
3177+
bool use_nofs_allocs = pwq->wq->flags & __WQ_NOFS;
3178+
unsigned long noio_flags;
3179+
unsigned long nofs_flags;
31753180
#ifdef CONFIG_LOCKDEP
31763181
/*
31773182
* It is permissible to free the struct work_struct from
@@ -3184,6 +3189,12 @@ __acquires(&pool->lock)
31843189

31853190
lockdep_copy_map(&lockdep_map, &work->lockdep_map);
31863191
#endif
3192+
/* Set inherited alloc flags */
3193+
if (use_noio_allocs)
3194+
noio_flags = memalloc_noio_save();
3195+
if (use_nofs_allocs)
3196+
nofs_flags = memalloc_nofs_save();
3197+
31873198
/* ensure we're on the correct CPU */
31883199
WARN_ON_ONCE(!(pool->flags & POOL_DISASSOCIATED) &&
31893200
raw_smp_processor_id() != pool->cpu);
@@ -3320,6 +3331,12 @@ __acquires(&pool->lock)
33203331

33213332
/* must be the last step, see the function comment */
33223333
pwq_dec_nr_in_flight(pwq, work_data);
3334+
3335+
/* Restore alloc flags */
3336+
if (use_nofs_allocs)
3337+
memalloc_nofs_restore(nofs_flags);
3338+
if (use_noio_allocs)
3339+
memalloc_noio_restore(noio_flags);
33233340
}
33243341

33253342
/**
@@ -5583,6 +5600,10 @@ struct workqueue_struct *alloc_workqueue(const char *fmt,
55835600

55845601
/* init wq */
55855602
wq->flags = flags;
5603+
if (current->flags & PF_MEMALLOC_NOIO)
5604+
wq->flags |= __WQ_NOIO;
5605+
if (current->flags & PF_MEMALLOC_NOFS)
5606+
wq->flags |= __WQ_NOFS;
55865607
wq->max_active = max_active;
55875608
wq->min_active = min(max_active, WQ_DFL_MIN_ACTIVE);
55885609
wq->saved_max_active = wq->max_active;

0 commit comments

Comments
 (0)