|
@@ -412,6 +412,7 @@ static void wb_exit(struct bdi_writeback *wb)
|
|
|
* protected.
|
|
|
*/
|
|
|
static DEFINE_SPINLOCK(cgwb_lock);
|
|
|
+static struct workqueue_struct *cgwb_release_wq;
|
|
|
|
|
|
/**
|
|
|
* wb_congested_get_create - get or create a wb_congested
|
|
@@ -522,7 +523,7 @@ static void cgwb_release(struct percpu_ref *refcnt)
|
|
|
{
|
|
|
struct bdi_writeback *wb = container_of(refcnt, struct bdi_writeback,
|
|
|
refcnt);
|
|
|
- schedule_work(&wb->release_work);
|
|
|
+ queue_work(cgwb_release_wq, &wb->release_work);
|
|
|
}
|
|
|
|
|
|
static void cgwb_kill(struct bdi_writeback *wb)
|
|
@@ -784,6 +785,21 @@ static void cgwb_bdi_register(struct backing_dev_info *bdi)
|
|
|
spin_unlock_irq(&cgwb_lock);
|
|
|
}
|
|
|
|
|
|
+static int __init cgwb_init(void)
|
|
|
+{
|
|
|
+ /*
|
|
|
+ * There can be many concurrent release work items overwhelming
|
|
|
+ * system_wq. Put them in a separate wq and limit concurrency.
|
|
|
+ * There's no point in executing many of these in parallel.
|
|
|
+ */
|
|
|
+ cgwb_release_wq = alloc_workqueue("cgwb_release", 0, 1);
|
|
|
+ if (!cgwb_release_wq)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+subsys_initcall(cgwb_init);
|
|
|
+
|
|
|
#else /* CONFIG_CGROUP_WRITEBACK */
|
|
|
|
|
|
static int cgwb_bdi_init(struct backing_dev_info *bdi)
|