mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-07-07 15:01:44 +00:00
writeback: make backing_dev_info host cgroup-specific bdi_writebacks
For the planned cgroup writeback support, on each bdi (backing_dev_info), each memcg will be served by a separate wb (bdi_writeback). This patch updates bdi so that a bdi can host multiple wbs (bdi_writebacks). On the default hierarchy, blkcg implicitly enables memcg. This allows using memcg's page ownership for attributing writeback IOs, and every memcg - blkcg combination can be served by its own wb by assigning a dedicated wb to each memcg. This means that there may be multiple wb's of a bdi mapped to the same blkcg. As congested state is per blkcg - bdi combination, those wb's should share the same congested state. This is achieved by tracking congested state via bdi_writeback_congested structs which are keyed by blkcg. bdi->wb remains unchanged and will keep serving the root cgroup. cgwb's (cgroup wb's) for non-root cgroups are created on-demand or looked up while dirtying an inode according to the memcg of the page being dirtied or current task. Each cgwb is indexed on bdi->cgwb_tree by its memcg id. Once an inode is associated with its wb, it can be retrieved using inode_to_wb(). Currently, none of the filesystems has FS_CGROUP_WRITEBACK and all pages will keep being associated with bdi->wb. v3: inode_attach_wb() in account_page_dirtied() moved inside mapping_cap_account_dirty() block where it's known to be !NULL. Also, an unnecessary NULL check before kfree() removed. Both detected by the kbuild bot. v2: Updated so that wb association is per inode and wb is per memcg rather than blkcg. Signed-off-by: Tejun Heo <tj@kernel.org> Cc: kbuild test robot <fengguang.wu@intel.com> Cc: Dan Carpenter <dan.carpenter@oracle.com> Cc: Jens Axboe <axboe@kernel.dk> Cc: Jan Kara <jack@suse.cz> Signed-off-by: Jens Axboe <axboe@fb.com>
This commit is contained in:
parent
89e9b9e07a
commit
52ebea749a
11 changed files with 698 additions and 11 deletions
|
@ -13,6 +13,7 @@
|
|||
#include <linux/sched.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/writeback.h>
|
||||
#include <linux/blk-cgroup.h>
|
||||
#include <linux/backing-dev-defs.h>
|
||||
|
||||
int __must_check bdi_init(struct backing_dev_info *bdi);
|
||||
|
@ -234,6 +235,16 @@ static inline int bdi_sched_wait(void *word)
|
|||
|
||||
#ifdef CONFIG_CGROUP_WRITEBACK
|
||||
|
||||
struct bdi_writeback_congested *
|
||||
wb_congested_get_create(struct backing_dev_info *bdi, int blkcg_id, gfp_t gfp);
|
||||
void wb_congested_put(struct bdi_writeback_congested *congested);
|
||||
struct bdi_writeback *wb_get_create(struct backing_dev_info *bdi,
|
||||
struct cgroup_subsys_state *memcg_css,
|
||||
gfp_t gfp);
|
||||
void __inode_attach_wb(struct inode *inode, struct page *page);
|
||||
void wb_memcg_offline(struct mem_cgroup *memcg);
|
||||
void wb_blkcg_offline(struct blkcg *blkcg);
|
||||
|
||||
/**
|
||||
* inode_cgwb_enabled - test whether cgroup writeback is enabled on an inode
|
||||
* @inode: inode of interest
|
||||
|
@ -250,6 +261,135 @@ static inline bool inode_cgwb_enabled(struct inode *inode)
|
|||
(inode->i_sb->s_type->fs_flags & FS_CGROUP_WRITEBACK);
|
||||
}
|
||||
|
||||
/**
|
||||
* wb_tryget - try to increment a wb's refcount
|
||||
* @wb: bdi_writeback to get
|
||||
*/
|
||||
static inline bool wb_tryget(struct bdi_writeback *wb)
|
||||
{
|
||||
if (wb != &wb->bdi->wb)
|
||||
return percpu_ref_tryget(&wb->refcnt);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* wb_get - increment a wb's refcount
|
||||
* @wb: bdi_writeback to get
|
||||
*/
|
||||
static inline void wb_get(struct bdi_writeback *wb)
|
||||
{
|
||||
if (wb != &wb->bdi->wb)
|
||||
percpu_ref_get(&wb->refcnt);
|
||||
}
|
||||
|
||||
/**
|
||||
* wb_put - decrement a wb's refcount
|
||||
* @wb: bdi_writeback to put
|
||||
*/
|
||||
static inline void wb_put(struct bdi_writeback *wb)
|
||||
{
|
||||
if (wb != &wb->bdi->wb)
|
||||
percpu_ref_put(&wb->refcnt);
|
||||
}
|
||||
|
||||
/**
|
||||
* wb_find_current - find wb for %current on a bdi
|
||||
* @bdi: bdi of interest
|
||||
*
|
||||
* Find the wb of @bdi which matches both the memcg and blkcg of %current.
|
||||
* Must be called under rcu_read_lock() which protects the returend wb.
|
||||
* NULL if not found.
|
||||
*/
|
||||
static inline struct bdi_writeback *wb_find_current(struct backing_dev_info *bdi)
|
||||
{
|
||||
struct cgroup_subsys_state *memcg_css;
|
||||
struct bdi_writeback *wb;
|
||||
|
||||
memcg_css = task_css(current, memory_cgrp_id);
|
||||
if (!memcg_css->parent)
|
||||
return &bdi->wb;
|
||||
|
||||
wb = radix_tree_lookup(&bdi->cgwb_tree, memcg_css->id);
|
||||
|
||||
/*
|
||||
* %current's blkcg equals the effective blkcg of its memcg. No
|
||||
* need to use the relatively expensive cgroup_get_e_css().
|
||||
*/
|
||||
if (likely(wb && wb->blkcg_css == task_css(current, blkio_cgrp_id)))
|
||||
return wb;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* wb_get_create_current - get or create wb for %current on a bdi
|
||||
* @bdi: bdi of interest
|
||||
* @gfp: allocation mask
|
||||
*
|
||||
* Equivalent to wb_get_create() on %current's memcg. This function is
|
||||
* called from a relatively hot path and optimizes the common cases using
|
||||
* wb_find_current().
|
||||
*/
|
||||
static inline struct bdi_writeback *
|
||||
wb_get_create_current(struct backing_dev_info *bdi, gfp_t gfp)
|
||||
{
|
||||
struct bdi_writeback *wb;
|
||||
|
||||
rcu_read_lock();
|
||||
wb = wb_find_current(bdi);
|
||||
if (wb && unlikely(!wb_tryget(wb)))
|
||||
wb = NULL;
|
||||
rcu_read_unlock();
|
||||
|
||||
if (unlikely(!wb)) {
|
||||
struct cgroup_subsys_state *memcg_css;
|
||||
|
||||
memcg_css = task_get_css(current, memory_cgrp_id);
|
||||
wb = wb_get_create(bdi, memcg_css, gfp);
|
||||
css_put(memcg_css);
|
||||
}
|
||||
return wb;
|
||||
}
|
||||
|
||||
/**
|
||||
* inode_attach_wb - associate an inode with its wb
|
||||
* @inode: inode of interest
|
||||
* @page: page being dirtied (may be NULL)
|
||||
*
|
||||
* If @inode doesn't have its wb, associate it with the wb matching the
|
||||
* memcg of @page or, if @page is NULL, %current. May be called w/ or w/o
|
||||
* @inode->i_lock.
|
||||
*/
|
||||
static inline void inode_attach_wb(struct inode *inode, struct page *page)
|
||||
{
|
||||
if (!inode->i_wb)
|
||||
__inode_attach_wb(inode, page);
|
||||
}
|
||||
|
||||
/**
|
||||
* inode_detach_wb - disassociate an inode from its wb
|
||||
* @inode: inode of interest
|
||||
*
|
||||
* @inode is being freed. Detach from its wb.
|
||||
*/
|
||||
static inline void inode_detach_wb(struct inode *inode)
|
||||
{
|
||||
if (inode->i_wb) {
|
||||
wb_put(inode->i_wb);
|
||||
inode->i_wb = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* inode_to_wb - determine the wb of an inode
|
||||
* @inode: inode of interest
|
||||
*
|
||||
* Returns the wb @inode is currently associated with.
|
||||
*/
|
||||
static inline struct bdi_writeback *inode_to_wb(struct inode *inode)
|
||||
{
|
||||
return inode->i_wb;
|
||||
}
|
||||
|
||||
#else /* CONFIG_CGROUP_WRITEBACK */
|
||||
|
||||
static inline bool inode_cgwb_enabled(struct inode *inode)
|
||||
|
@ -257,6 +397,61 @@ static inline bool inode_cgwb_enabled(struct inode *inode)
|
|||
return false;
|
||||
}
|
||||
|
||||
static inline struct bdi_writeback_congested *
|
||||
wb_congested_get_create(struct backing_dev_info *bdi, int blkcg_id, gfp_t gfp)
|
||||
{
|
||||
return bdi->wb.congested;
|
||||
}
|
||||
|
||||
static inline void wb_congested_put(struct bdi_writeback_congested *congested)
|
||||
{
|
||||
}
|
||||
|
||||
static inline bool wb_tryget(struct bdi_writeback *wb)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void wb_get(struct bdi_writeback *wb)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void wb_put(struct bdi_writeback *wb)
|
||||
{
|
||||
}
|
||||
|
||||
static inline struct bdi_writeback *wb_find_current(struct backing_dev_info *bdi)
|
||||
{
|
||||
return &bdi->wb;
|
||||
}
|
||||
|
||||
static inline struct bdi_writeback *
|
||||
wb_get_create_current(struct backing_dev_info *bdi, gfp_t gfp)
|
||||
{
|
||||
return &bdi->wb;
|
||||
}
|
||||
|
||||
static inline void inode_attach_wb(struct inode *inode, struct page *page)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void inode_detach_wb(struct inode *inode)
|
||||
{
|
||||
}
|
||||
|
||||
static inline struct bdi_writeback *inode_to_wb(struct inode *inode)
|
||||
{
|
||||
return &inode_to_bdi(inode)->wb;
|
||||
}
|
||||
|
||||
static inline void wb_memcg_offline(struct mem_cgroup *memcg)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void wb_blkcg_offline(struct blkcg *blkcg)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_CGROUP_WRITEBACK */
|
||||
|
||||
#endif /* _LINUX_BACKING_DEV_H */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue