Introduce a new macro for_each_bdi_wb_ctx to iterate over multiple writeback ctxs. Added logic for allocation, init, free, registration and unregistration of multiple writeback contexts within a bdi.
Signed-off-by: Kundan Kumar <kundan.ku...@samsung.com> Signed-off-by: Anuj Gupta <anuj2...@samsung.com> --- include/linux/backing-dev.h | 4 ++ mm/backing-dev.c | 79 +++++++++++++++++++++++++++---------- 2 files changed, 62 insertions(+), 21 deletions(-) diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h index 894968e98dd8..fbccb483e59c 100644 --- a/include/linux/backing-dev.h +++ b/include/linux/backing-dev.h @@ -148,6 +148,10 @@ static inline bool mapping_can_writeback(struct address_space *mapping) return inode_to_bdi(mapping->host)->capabilities & BDI_CAP_WRITEBACK; } +#define for_each_bdi_wb_ctx(bdi, wb_ctx) \ + for (int __i = 0; __i < (bdi)->nr_wb_ctx \ + && ((wb_ctx) = (bdi)->wb_ctx_arr[__i]) != NULL; __i++) + static inline struct bdi_writeback_ctx * fetch_bdi_writeback_ctx(struct inode *inode) { diff --git a/mm/backing-dev.c b/mm/backing-dev.c index 0efa9632011a..adf87b036827 100644 --- a/mm/backing-dev.c +++ b/mm/backing-dev.c @@ -836,16 +836,19 @@ struct bdi_writeback *wb_get_create(struct backing_dev_info *bdi, static int cgwb_bdi_init(struct backing_dev_info *bdi) { int ret; - struct bdi_writeback_ctx *bdi_wb_ctx = bdi->wb_ctx_arr[0]; + struct bdi_writeback_ctx *bdi_wb_ctx; - INIT_RADIX_TREE(&bdi_wb_ctx->cgwb_tree, GFP_ATOMIC); - mutex_init(&bdi->cgwb_release_mutex); - init_rwsem(&bdi_wb_ctx->wb_switch_rwsem); + for_each_bdi_wb_ctx(bdi, bdi_wb_ctx) { + INIT_RADIX_TREE(&bdi_wb_ctx->cgwb_tree, GFP_ATOMIC); + mutex_init(&bdi->cgwb_release_mutex); + init_rwsem(&bdi_wb_ctx->wb_switch_rwsem); - ret = wb_init(&bdi_wb_ctx->wb, bdi, GFP_KERNEL); - if (!ret) { - bdi_wb_ctx->wb.memcg_css = &root_mem_cgroup->css; - bdi_wb_ctx->wb.blkcg_css = blkcg_root_css; + ret = wb_init(&bdi_wb_ctx->wb, bdi, GFP_KERNEL); + if (!ret) { + bdi_wb_ctx->wb.memcg_css = &root_mem_cgroup->css; + bdi_wb_ctx->wb.blkcg_css = blkcg_root_css; + } else + return ret; } return ret; } @@ -992,7 +995,16 @@ subsys_initcall(cgwb_init); static int cgwb_bdi_init(struct backing_dev_info *bdi) { - return wb_init(&bdi->wb_ctx_arr[0]->wb, bdi, GFP_KERNEL); + struct bdi_writeback_ctx *bdi_wb_ctx; + + for_each_bdi_wb_ctx(bdi, bdi_wb_ctx) { + int ret; + + ret = wb_init(&bdi_wb_ctx->wb, bdi, GFP_KERNEL); + if (ret) + return ret; + } + return 0; } static void cgwb_bdi_unregister(struct backing_dev_info *bdi, @@ -1026,10 +1038,19 @@ int bdi_init(struct backing_dev_info *bdi) sizeof(struct bdi_writeback_ctx *), GFP_KERNEL); INIT_LIST_HEAD(&bdi->bdi_list); - bdi->wb_ctx_arr[0] = (struct bdi_writeback_ctx *) - kzalloc(sizeof(struct bdi_writeback_ctx), GFP_KERNEL); - INIT_LIST_HEAD(&bdi->wb_ctx_arr[0]->wb_list); - init_waitqueue_head(&bdi->wb_ctx_arr[0]->wb_waitq); + for (int i = 0; i < bdi->nr_wb_ctx; i++) { + bdi->wb_ctx_arr[i] = (struct bdi_writeback_ctx *) + kzalloc(sizeof(struct bdi_writeback_ctx), GFP_KERNEL); + if (!bdi->wb_ctx_arr[i]) { + pr_err("Failed to allocate %d", i); + while (--i >= 0) + kfree(bdi->wb_ctx_arr[i]); + kfree(bdi->wb_ctx_arr); + return -ENOMEM; + } + INIT_LIST_HEAD(&bdi->wb_ctx_arr[i]->wb_list); + init_waitqueue_head(&bdi->wb_ctx_arr[i]->wb_waitq); + } bdi->last_bdp_sleep = jiffies; return cgwb_bdi_init(bdi); @@ -1038,13 +1059,16 @@ int bdi_init(struct backing_dev_info *bdi) struct backing_dev_info *bdi_alloc(int node_id) { struct backing_dev_info *bdi; + struct bdi_writeback_ctx *bdi_wb_ctx; bdi = kzalloc_node(sizeof(*bdi), GFP_KERNEL, node_id); if (!bdi) return NULL; if (bdi_init(bdi)) { - kfree(bdi->wb_ctx_arr[0]); + for_each_bdi_wb_ctx(bdi, bdi_wb_ctx) { + kfree(bdi_wb_ctx); + } kfree(bdi->wb_ctx_arr); kfree(bdi); return NULL; @@ -1109,6 +1133,7 @@ int bdi_register_va(struct backing_dev_info *bdi, const char *fmt, va_list args) { struct device *dev; struct rb_node *parent, **p; + struct bdi_writeback_ctx *bdi_wb_ctx; if (bdi->dev) /* The driver needs to use separate queues per device */ return 0; @@ -1118,8 +1143,11 @@ int bdi_register_va(struct backing_dev_info *bdi, const char *fmt, va_list args) if (IS_ERR(dev)) return PTR_ERR(dev); - cgwb_bdi_register(bdi, bdi->wb_ctx_arr[0]); - set_bit(WB_registered, &bdi->wb_ctx_arr[0]->wb.state); + for_each_bdi_wb_ctx(bdi, bdi_wb_ctx) { + cgwb_bdi_register(bdi, bdi_wb_ctx); + set_bit(WB_registered, &bdi_wb_ctx->wb.state); + } + bdi->dev = dev; bdi_debug_register(bdi, dev_name(dev)); @@ -1174,12 +1202,17 @@ static void bdi_remove_from_list(struct backing_dev_info *bdi) void bdi_unregister(struct backing_dev_info *bdi) { + struct bdi_writeback_ctx *bdi_wb_ctx; + timer_delete_sync(&bdi->laptop_mode_wb_timer); /* make sure nobody finds us on the bdi_list anymore */ bdi_remove_from_list(bdi); - wb_shutdown(&bdi->wb_ctx_arr[0]->wb); - cgwb_bdi_unregister(bdi, bdi->wb_ctx_arr[0]); + + for_each_bdi_wb_ctx(bdi, bdi_wb_ctx) { + wb_shutdown(&bdi_wb_ctx->wb); + cgwb_bdi_unregister(bdi, bdi_wb_ctx); + } /* * If this BDI's min ratio has been set, use bdi_set_min_ratio() to @@ -1205,11 +1238,15 @@ static void release_bdi(struct kref *ref) { struct backing_dev_info *bdi = container_of(ref, struct backing_dev_info, refcnt); + struct bdi_writeback_ctx *bdi_wb_ctx; WARN_ON_ONCE(bdi->dev); - WARN_ON_ONCE(test_bit(WB_registered, &bdi->wb_ctx_arr[0]->wb.state)); - wb_exit(&bdi->wb_ctx_arr[0]->wb); - kfree(bdi->wb_ctx_arr[0]); + + for_each_bdi_wb_ctx(bdi, bdi_wb_ctx) { + WARN_ON_ONCE(test_bit(WB_registered, &bdi_wb_ctx->wb.state)); + wb_exit(&bdi_wb_ctx->wb); + kfree(bdi_wb_ctx); + } kfree(bdi->wb_ctx_arr); kfree(bdi); } -- 2.25.1 _______________________________________________ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel