cregit-Linux how code gets into the kernel

Release 4.8 mm/backing-dev.c

Directory: mm
#include <linux/wait.h>
#include <linux/backing-dev.h>
#include <linux/kthread.h>
#include <linux/freezer.h>
#include <linux/fs.h>
#include <linux/pagemap.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/module.h>
#include <linux/writeback.h>
#include <linux/device.h>
#include <trace/events/writeback.h>


static atomic_long_t bdi_seq = ATOMIC_LONG_INIT(0);


struct backing_dev_info noop_backing_dev_info = {
	.name		= "noop",
	.capabilities	= BDI_CAP_NO_ACCT_AND_WRITEBACK,
};

EXPORT_SYMBOL_GPL(noop_backing_dev_info);


static struct class *bdi_class;

/*
 * bdi_lock protects updates to bdi_list. bdi_list has RCU reader side
 * locking.
 */

DEFINE_SPINLOCK(bdi_lock);

LIST_HEAD(bdi_list);

/* bdi_wq serves all asynchronous writeback tasks */

struct workqueue_struct *bdi_wq;

#ifdef CONFIG_DEBUG_FS
#include <linux/debugfs.h>
#include <linux/seq_file.h>


static struct dentry *bdi_debug_root;


static void bdi_debug_init(void) { bdi_debug_root = debugfs_create_dir("bdi", NULL); }

Contributors

PersonTokensPropCommitsCommitProp
miklos szeredimiklos szeredi17100.00%1100.00%
Total17100.00%1100.00%


static int bdi_debug_stats_show(struct seq_file *m, void *v) { struct backing_dev_info *bdi = m->private; struct bdi_writeback *wb = &bdi->wb; unsigned long background_thresh; unsigned long dirty_thresh; unsigned long wb_thresh; unsigned long nr_dirty, nr_io, nr_more_io, nr_dirty_time; struct inode *inode; nr_dirty = nr_io = nr_more_io = nr_dirty_time = 0; spin_lock(&wb->list_lock); list_for_each_entry(inode, &wb->b_dirty, i_io_list) nr_dirty++; list_for_each_entry(inode, &wb->b_io, i_io_list) nr_io++; list_for_each_entry(inode, &wb->b_more_io, i_io_list) nr_more_io++; list_for_each_entry(inode, &wb->b_dirty_time, i_io_list) if (inode->i_state & I_DIRTY_TIME) nr_dirty_time++; spin_unlock(&wb->list_lock); global_dirty_limits(&background_thresh, &dirty_thresh); wb_thresh = wb_calc_thresh(wb, dirty_thresh); #define K(x) ((x) << (PAGE_SHIFT - 10)) seq_printf(m, "BdiWriteback: %10lu kB\n" "BdiReclaimable: %10lu kB\n" "BdiDirtyThresh: %10lu kB\n" "DirtyThresh: %10lu kB\n" "BackgroundThresh: %10lu kB\n" "BdiDirtied: %10lu kB\n" "BdiWritten: %10lu kB\n" "BdiWriteBandwidth: %10lu kBps\n" "b_dirty: %10lu\n" "b_io: %10lu\n" "b_more_io: %10lu\n" "b_dirty_time: %10lu\n" "bdi_list: %10u\n" "state: %10lx\n", (unsigned long) K(wb_stat(wb, WB_WRITEBACK)), (unsigned long) K(wb_stat(wb, WB_RECLAIMABLE)), K(wb_thresh), K(dirty_thresh), K(background_thresh), (unsigned long) K(wb_stat(wb, WB_DIRTIED)), (unsigned long) K(wb_stat(wb, WB_WRITTEN)), (unsigned long) K(wb->write_bandwidth), nr_dirty, nr_io, nr_more_io, nr_dirty_time, !list_empty(&bdi->bdi_list), bdi->wb.state); #undef K return 0; }

Contributors

PersonTokensPropCommitsCommitProp
miklos szeredimiklos szeredi9532.20%16.67%
jens axboejens axboe8528.81%16.67%
fengguang wufengguang wu4113.90%320.00%
theodore tsotheodore tso258.47%16.67%
tejun heotejun heo206.78%426.67%
christoph hellwigchristoph hellwig113.73%213.33%
jan karajan kara113.73%16.67%
dave chinnerdave chinner41.36%16.67%
david rientjesdavid rientjes31.02%16.67%
Total295100.00%15100.00%


static int bdi_debug_stats_open(struct inode *inode, struct file *file) { return single_open(file, bdi_debug_stats_show, inode->i_private); }

Contributors

PersonTokensPropCommitsCommitProp
miklos szeredimiklos szeredi28100.00%1100.00%
Total28100.00%1100.00%

static const struct file_operations bdi_debug_stats_fops = { .open = bdi_debug_stats_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, };
static void bdi_debug_register(struct backing_dev_info *bdi, const char *name) { bdi->debug_dir = debugfs_create_dir(name, bdi_debug_root); bdi->debug_stats = debugfs_create_file("stats", 0444, bdi->debug_dir, bdi, &bdi_debug_stats_fops); }

Contributors

PersonTokensPropCommitsCommitProp
miklos szeredimiklos szeredi47100.00%1100.00%
Total47100.00%1100.00%


static void bdi_debug_unregister(struct backing_dev_info *bdi) { debugfs_remove(bdi->debug_stats); debugfs_remove(bdi->debug_dir); }

Contributors

PersonTokensPropCommitsCommitProp
miklos szeredimiklos szeredi25100.00%1100.00%
Total25100.00%1100.00%

#else
static inline void bdi_debug_init(void) { }

Contributors

PersonTokensPropCommitsCommitProp
miklos szeredimiklos szeredi8100.00%1100.00%
Total8100.00%1100.00%


static inline void bdi_debug_register(struct backing_dev_info *bdi, const char *name) { }

Contributors

PersonTokensPropCommitsCommitProp
miklos szeredimiklos szeredi16100.00%1100.00%
Total16100.00%1100.00%


static inline void bdi_debug_unregister(struct backing_dev_info *bdi) { }

Contributors

PersonTokensPropCommitsCommitProp
miklos szeredimiklos szeredi11100.00%1100.00%
Total11100.00%1100.00%

#endif
static ssize_t read_ahead_kb_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct backing_dev_info *bdi = dev_get_drvdata(dev); unsigned long read_ahead_kb; ssize_t ret; ret = kstrtoul(buf, 10, &read_ahead_kb); if (ret < 0) return ret; bdi->ra_pages = read_ahead_kb >> (PAGE_SHIFT - 10); return count; }

Contributors

PersonTokensPropCommitsCommitProp
peter zijlstrapeter zijlstra6685.71%150.00%
namjae jeonnamjae jeon1114.29%150.00%
Total77100.00%2100.00%

#define K(pages) ((pages) << (PAGE_SHIFT - 10)) #define BDI_SHOW(name, expr) \ static ssize_t name##_show(struct device *dev, \ struct device_attribute *attr, char *page) \ { \ struct backing_dev_info *bdi = dev_get_drvdata(dev); \ \ return snprintf(page, PAGE_SIZE-1, "%lld\n", (long long)expr); \ } \ static DEVICE_ATTR_RW(name); BDI_SHOW(read_ahead_kb, K(bdi->ra_pages))
static ssize_t min_ratio_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct backing_dev_info *bdi = dev_get_drvdata(dev); unsigned int ratio; ssize_t ret; ret = kstrtouint(buf, 10, &ratio); if (ret < 0) return ret; ret = bdi_set_min_ratio(bdi, ratio); if (!ret) ret = count; return ret; }

Contributors

PersonTokensPropCommitsCommitProp
peter zijlstrapeter zijlstra7387.95%150.00%
namjae jeonnamjae jeon1012.05%150.00%
Total83100.00%2100.00%

BDI_SHOW(min_ratio, bdi->min_ratio)
static ssize_t max_ratio_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct backing_dev_info *bdi = dev_get_drvdata(dev); unsigned int ratio; ssize_t ret; ret = kstrtouint(buf, 10, &ratio); if (ret < 0) return ret; ret = bdi_set_max_ratio(bdi, ratio); if (!ret) ret = count; return ret; }

Contributors

PersonTokensPropCommitsCommitProp
peter zijlstrapeter zijlstra7387.95%150.00%
namjae jeonnamjae jeon1012.05%150.00%
Total83100.00%2100.00%

BDI_SHOW(max_ratio, bdi->max_ratio)
static ssize_t stable_pages_required_show(struct device *dev, struct device_attribute *attr, char *page) { struct backing_dev_info *bdi = dev_get_drvdata(dev); return snprintf(page, PAGE_SIZE-1, "%d\n", bdi_cap_stable_pages_required(bdi) ? 1 : 0); }

Contributors

PersonTokensPropCommitsCommitProp
darrick j. wongdarrick j. wong51100.00%1100.00%
Total51100.00%1100.00%

static DEVICE_ATTR_RO(stable_pages_required); static struct attribute *bdi_dev_attrs[] = { &dev_attr_read_ahead_kb.attr, &dev_attr_min_ratio.attr, &dev_attr_max_ratio.attr, &dev_attr_stable_pages_required.attr, NULL, }; ATTRIBUTE_GROUPS(bdi_dev);
static __init int bdi_class_init(void) { bdi_class = class_create(THIS_MODULE, "bdi"); if (IS_ERR(bdi_class)) return PTR_ERR(bdi_class); bdi_class->dev_groups = bdi_dev_groups; bdi_debug_init(); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
peter zijlstrapeter zijlstra2558.14%125.00%
anton blanchardanton blanchard1330.23%125.00%
miklos szeredimiklos szeredi36.98%125.00%
greg kroah-hartmangreg kroah-hartman24.65%125.00%
Total43100.00%4100.00%

postcore_initcall(bdi_class_init);
static int __init default_bdi_init(void) { int err; bdi_wq = alloc_workqueue("writeback", WQ_MEM_RECLAIM | WQ_FREEZABLE | WQ_UNBOUND | WQ_SYSFS, 0); if (!bdi_wq) return -ENOMEM; err = bdi_init(&noop_backing_dev_info); return err; }

Contributors

PersonTokensPropCommitsCommitProp
tejun heotejun heo2653.06%250.00%
jens axboejens axboe2040.82%125.00%
jan karajan kara36.12%125.00%
Total49100.00%4100.00%

subsys_initcall(default_bdi_init); /* * This function is used when the first inode for this wb is marked dirty. It * wakes-up the corresponding bdi thread which should then take care of the * periodic background write-out of dirty inodes. Since the write-out would * starts only 'dirty_writeback_interval' centisecs from now anyway, we just * set up a timer which wakes the bdi thread up later. * * Note, we wouldn't bother setting up the timer, but this function is on the * fast-path (used by '__mark_inode_dirty()'), so we save few context switches * by delaying the wake-up. * * We have to be careful not to postpone flush work if it is scheduled for * earlier. Thus we use queue_delayed_work(). */
void wb_wakeup_delayed(struct bdi_writeback *wb) { unsigned long timeout; timeout = msecs_to_jiffies(dirty_writeback_interval * 10); spin_lock_bh(&wb->work_lock); if (test_bit(WB_registered, &wb->state)) queue_delayed_work(bdi_wq, &wb->dwork, timeout); spin_unlock_bh(&wb->work_lock); }

Contributors

PersonTokensPropCommitsCommitProp
artem bityutskiyartem bityutskiy2742.86%116.67%
jan karajan kara2234.92%116.67%
tejun heotejun heo1320.63%350.00%
derek basehorederek basehore11.59%116.67%
Total63100.00%6100.00%

/* * Initial write bandwidth: 100 MB/s */ #define INIT_BW (100 << (20 - PAGE_SHIFT))
static int wb_init(struct bdi_writeback *wb, struct backing_dev_info *bdi, int blkcg_id, gfp_t gfp) { int i, err; memset(wb, 0, sizeof(*wb)); wb->bdi = bdi; wb->last_old_flush = jiffies; INIT_LIST_HEAD(&wb->b_dirty); INIT_LIST_HEAD(&wb->b_io); INIT_LIST_HEAD(&wb->b_more_io); INIT_LIST_HEAD(&wb->b_dirty_time); spin_lock_init(&wb->list_lock); wb->bw_time_stamp = jiffies; wb->balanced_dirty_ratelimit = INIT_BW; wb->dirty_ratelimit = INIT_BW; wb->write_bandwidth = INIT_BW; wb->avg_write_bandwidth = INIT_BW; spin_lock_init(&wb->work_lock); INIT_LIST_HEAD(&wb->work_list); INIT_DELAYED_WORK(&wb->dwork, wb_workfn); wb->congested = wb_congested_get_create(bdi, blkcg_id, gfp); if (!wb->congested) return -ENOMEM; err = fprop_local_init_percpu(&wb->completions, gfp); if (err) goto out_put_cong; for (i = 0; i < NR_WB_STAT_ITEMS; i++) { err = percpu_counter_init(&wb->stat[i], 0, gfp); if (err) goto out_destroy_stat; } return 0; out_destroy_stat: while (i--) percpu_counter_destroy(&wb->stat[i]); fprop_local_destroy_percpu(&wb->completions); out_put_cong: wb_congested_put(wb->congested); return err; }

Contributors

PersonTokensPropCommitsCommitProp
tejun heotejun heo19772.69%541.67%
jens axboejens axboe279.96%216.67%
artem bityutskiyartem bityutskiy259.23%18.33%
peter zijlstrapeter zijlstra134.80%18.33%
david chinnerdavid chinner41.48%18.33%
jan karajan kara41.48%18.33%
rasmus villemoesrasmus villemoes10.37%18.33%
Total271100.00%12100.00%

/* * Remove bdi from the global list and shutdown any threads we have running */
static void wb_shutdown(struct bdi_writeback *wb) { /* Make sure nobody queues further work */ spin_lock_bh(&wb->work_lock); if (!test_and_clear_bit(WB_registered, &wb->state)) { spin_unlock_bh(&wb->work_lock); return; } spin_unlock_bh(&wb->work_lock); /* * Drain work list and shutdown the delayed_work. !WB_registered * tells wb_workfn() that @wb is dying and its work_list needs to * be drained no matter what. */ mod_delayed_work(bdi_wq, &wb->dwork, 0); flush_delayed_work(&wb->dwork); WARN_ON(!list_empty(&wb->work_list)); }

Contributors

PersonTokensPropCommitsCommitProp
tejun heotejun heo3541.18%333.33%
jan karajan kara1821.18%111.11%
christoph hellwigchristoph hellwig1618.82%222.22%
jens axboejens axboe1315.29%222.22%
rabin vincentrabin vincent33.53%111.11%
Total85100.00%9100.00%


static void wb_exit(struct bdi_writeback *wb) { int i; WARN_ON(delayed_work_pending(&wb->dwork)); for (i = 0; i < NR_WB_STAT_ITEMS; i++) percpu_counter_destroy(&wb->stat[i]); fprop_local_destroy_percpu(&wb->completions); wb_congested_put(wb->congested); }

Contributors

PersonTokensPropCommitsCommitProp
tejun heotejun heo5789.06%266.67%
artem bityutskiyartem bityutskiy710.94%133.33%
Total64100.00%3100.00%

#ifdef CONFIG_CGROUP_WRITEBACK #include <linux/memcontrol.h> /* * cgwb_lock protects bdi->cgwb_tree, bdi->cgwb_congested_tree, * blkcg->cgwb_list, and memcg->cgwb_list. bdi->cgwb_tree is also RCU * protected. cgwb_release_wait is used to wait for the completion of cgwb * releases from bdi destruction path. */ static DEFINE_SPINLOCK(cgwb_lock); static DECLARE_WAIT_QUEUE_HEAD(cgwb_release_wait); /** * wb_congested_get_create - get or create a wb_congested * @bdi: associated bdi * @blkcg_id: ID of the associated blkcg * @gfp: allocation mask * * Look up the wb_congested for @blkcg_id on @bdi. If missing, create one. * The returned wb_congested has its reference count incremented. Returns * NULL on failure. */
struct bdi_writeback_congested * wb_congested_get_create(struct backing_dev_info *bdi, int blkcg_id, gfp_t gfp) { struct bdi_writeback_congested *new_congested = NULL, *congested; struct rb_node **node, *parent; unsigned long flags; retry: spin_lock_irqsave(&cgwb_lock, flags); node = &bdi->cgwb_congested_tree.rb_node; parent = NULL; while (*node != NULL) { parent = *node; congested = container_of(parent, struct bdi_writeback_congested, rb_node); if (congested->blkcg_id < blkcg_id) node = &parent->rb_left; else if (congested->blkcg_id > blkcg_id) node = &parent->rb_right; else goto found; } if (new_congested) { /* !found and storage for new one already allocated, insert */ congested = new_congested; new_congested = NULL; rb_link_node(&congested->rb_node, parent, node); rb_insert_color(&congested->rb_node, &bdi->cgwb_congested_tree); goto found; } spin_unlock_irqrestore(&cgwb_lock, flags); /* allocate storage for new one and retry */ new_congested = kzalloc(sizeof(*new_congested), gfp); if (!new_congested) return NULL; atomic_set(&new_congested->refcnt, 0); new_congested->bdi = bdi; new_congested->blkcg_id = blkcg_id; goto retry; found: atomic_inc(&congested->refcnt); spin_unlock_irqrestore(&cgwb_lock, flags); kfree(new_congested); return congested; }

Contributors

PersonTokensPropCommitsCommitProp
tejun heotejun heo249100.00%1100.00%
Total249100.00%1100.00%

/** * wb_congested_put - put a wb_congested * @congested: wb_congested to put * * Put @congested and destroy it if the refcnt reaches zero. */
void wb_congested_put(struct bdi_writeback_congested *congested) { unsigned long flags; local_irq_save(flags); if (!atomic_dec_and_lock(&congested->refcnt, &cgwb_lock)) { local_irq_restore(flags); return; } /* bdi might already have been destroyed leaving @congested unlinked */ if (congested->bdi) { rb_erase(&congested->rb_node, &congested->bdi->cgwb_congested_tree); congested->bdi = NULL; } spin_unlock_irqrestore(&cgwb_lock, flags); kfree(congested); }

Contributors

PersonTokensPropCommitsCommitProp
tejun heotejun heo84100.00%2100.00%
Total84100.00%2100.00%


static void cgwb_release_workfn(struct work_struct *work) { struct bdi_writeback *wb = container_of(work, struct bdi_writeback, release_work); struct backing_dev_info *bdi = wb->bdi; spin_lock_irq(&cgwb_lock); list_del_rcu(&wb->bdi_node); spin_unlock_irq(&cgwb_lock); wb_shutdown(wb); css_put(wb->memcg_css); css_put(wb->blkcg_css); fprop_local_destroy_percpu(&wb->memcg_completions); percpu_ref_exit(&wb->refcnt); wb_exit(wb); kfree_rcu(wb, rcu); if (atomic_dec_and_test(&bdi->usage_cnt)) wake_up_all(&cgwb_release_wait); }

Contributors

PersonTokensPropCommitsCommitProp
tejun heotejun heo118100.00%3100.00%
Total118100.00%3100.00%


static void cgwb_release(struct percpu_ref *refcnt) { struct bdi_writeback *wb = container_of(refcnt, struct bdi_writeback, refcnt); schedule_work(&wb->release_work); }

Contributors

PersonTokensPropCommitsCommitProp
tejun heotejun heo34100.00%1100.00%
Total34100.00%1100.00%


static void cgwb_kill(struct bdi_writeback *wb) { lockdep_assert_held(&cgwb_lock); WARN_ON(!radix_tree_delete(&wb->bdi->cgwb_tree, wb->memcg_css->id)); list_del(&wb->memcg_node); list_del(&wb->blkcg_node); percpu_ref_kill(&wb->refcnt); }

Contributors

PersonTokensPropCommitsCommitProp
tejun heotejun heo61100.00%1100.00%
Total61100.00%1100.00%


static int cgwb_create(struct backing_dev_info *bdi, struct cgroup_subsys_state *memcg_css, gfp_t gfp) { struct mem_cgroup *memcg; struct cgroup_subsys_state *blkcg_css; struct blkcg *blkcg; struct list_head *memcg_cgwb_list, *blkcg_cgwb_list; struct bdi_writeback *wb; unsigned long flags; int ret = 0; memcg = mem_cgroup_from_css(memcg_css); blkcg_css = cgroup_get_e_css(memcg_css->cgroup, &io_cgrp_subsys); blkcg = css_to_blkcg(blkcg_css); memcg_cgwb_list = mem_cgroup_cgwb_list(memcg); blkcg_cgwb_list = &blkcg->cgwb_list; /* look up again under lock and discard on blkcg mismatch */ spin_lock_irqsave(&cgwb_lock, flags); wb = radix_tree_lookup(&bdi->cgwb_tree, memcg_css->id); if (wb && wb->blkcg_css != blkcg_css) { cgwb_kill(wb); wb = NULL; } spin_unlock_irqrestore(&cgwb_lock, flags); if (wb) goto out_put; /* need to create a new one */ wb = kmalloc(sizeof(*wb), gfp); if (!wb) return -ENOMEM; ret = wb_init(wb, bdi, blkcg_css->id, gfp); if (ret) goto err_free; ret = percpu_ref_init(&wb->refcnt, cgwb_release, 0, gfp); if (ret) goto err_wb_exit; ret = fprop_local_init_percpu(&wb->memcg_completions, gfp); if (ret) goto err_ref_exit; wb->memcg_css = memcg_css; wb->blkcg_css = blkcg_css; INIT_WORK(&wb->release_work, cgwb_release_workfn); set_bit(WB_registered, &wb->state); /* * The root wb determines the registered state of the whole bdi and * memcg_cgwb_list and blkcg_cgwb_list's next pointers indicate * whether they're still online. Don't link @wb if any is dead. * See wb_memcg_offline() and wb_blkcg_offline(). */ ret = -ENODEV; spin_lock_irqsave(&cgwb_lock, flags); if (test_bit(WB_registered, &bdi->wb.state) && blkcg_cgwb_list->next && memcg_cgwb_list->next) { /* we might have raced another instance of this function */ ret = radix_tree_insert(&bdi->cgwb_tree, memcg_css->id, wb); if (!ret) { atomic_inc(&bdi->usage_cnt); list_add_tail_rcu(&wb->bdi_node, &bdi->wb_list); list_add(&wb->memcg_node, memcg_cgwb_list); list_add(&wb->blkcg_node, blkcg_cgwb_list); css_get(memcg_css); css_get(blkcg_css); } } spin_unlock_irqrestore(&cgwb_lock, flags); if (ret) { if (ret == -EEXIST) ret = 0; goto err_fprop_exit; } goto out_put; err_fprop_exit: fprop_local_destroy_percpu(&wb->memcg_completions); err_ref_exit: percpu_ref_exit(&wb->refcnt); err_wb_exit: wb_exit(wb); err_free: kfree(wb); out_put: css_put(blkcg_css); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
tejun heotejun heo462100.00%5100.00%
Total462100.00%5100.00%

/** * wb_get_create - get wb for a given memcg, create if necessary * @bdi: target bdi * @memcg_css: cgroup_subsys_state of the target memcg (must have positive ref) * @gfp: allocation mask to use * * Try to get the wb for @memcg_css on @bdi. If it doesn't exist, try to * create one. The returned wb has its refcount incremented. * * This function uses css_get() on @memcg_css and thus expects its refcnt * to be positive on invocation. IOW, rcu_read_lock() protection on * @memcg_css isn't enough. try_get it before calling this function. * * A wb is keyed by its associated memcg. As blkcg implicitly enables * memcg on the default hierarchy, memcg association is guaranteed to be * more specific (equal or descendant to the associated blkcg) and thus can * identify both the memcg and blkcg associations. * * Because the blkcg associated with a memcg may change as blkcg is enabled * and disabled closer to root in the hierarchy, each wb keeps track of * both the memcg and blkcg associated with it and verifies the blkcg on * each lookup. On mismatch, the existing wb is discarded and a new one is * created. */
struct bdi_writeback *wb_get_create(struct backing_dev_info *bdi, struct cgroup_subsys_state *memcg_css, gfp_t gfp) { struct bdi_writeback *wb; might_sleep_if(gfpflags_allow_blocking(gfp)); if (!memcg_css->parent) return &bdi->wb; do { rcu_read_lock(); wb = radix_tree_lookup(&bdi->cgwb_tree, memcg_css->id); if (wb) { struct cgroup_subsys_state *blkcg_css; /* see whether the blkcg association has changed */ blkcg_css = cgroup_get_e_css(memcg_css->cgroup, &io_cgrp_subsys); if (unlikely(wb->blkcg_css != blkcg_css || !wb_tryget(wb))) wb = NULL; css_put(blkcg_css); } rcu_read_unlock(); } while (!wb && !cgwb_create(bdi, memcg_css, gfp)); return wb; }

Contributors

PersonTokensPropCommitsCommitProp
tejun heotejun heo13597.83%266.67%
mel gormanmel gorman32.17%133.33%
Total138100.00%3100.00%


static int cgwb_bdi_init(struct backing_dev_info *bdi) { int ret; INIT_RADIX_TREE(&bdi->cgwb_tree, GFP_ATOMIC); bdi->cgwb_congested_tree = RB_ROOT; atomic_set(&bdi->usage_cnt, 1); ret = wb_init(&bdi->wb, bdi, 1, GFP_KERNEL); if (!ret) { bdi->wb.memcg_css = &root_mem_cgroup->css; bdi->wb.blkcg_css = blkcg_root_css; } return ret; }

Contributors

PersonTokensPropCommitsCommitProp
tejun heotejun heo8195.29%266.67%
johannes weinerjohannes weiner44.71%133.33%
Total85100.00%3100.00%


static void cgwb_bdi_destroy(struct backing_dev_info *bdi) { struct radix_tree_iter iter; struct rb_node *rbn; void **