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 **slot; WARN_ON(test_bit(WB_registered, &bdi->wb.state)); spin_lock_irq(&cgwb_lock); radix_tree_for_each_slot(slot, &bdi->cgwb_tree, &iter, 0) cgwb_kill(*slot); while ((rbn = rb_first(&bdi->cgwb_congested_tree))) { struct bdi_writeback_congested *congested = rb_entry(rbn, struct bdi_writeback_congested, rb_node); rb_erase(rbn, &bdi->cgwb_congested_tree); congested->bdi = NULL; /* mark @congested unlinked */ } spin_unlock_irq(&cgwb_lock); /* * All cgwb's and their congested states must be shutdown and * released before returning. Drain the usage counter to wait for * all cgwb's and cgwb_congested's ever created on @bdi. */ atomic_dec(&bdi->usage_cnt); wait_event(cgwb_release_wait, !atomic_read(&bdi->usage_cnt)); }

Contributors

PersonTokensPropCommitsCommitProp
tejun heotejun heo139100.00%3100.00%
Total139100.00%3100.00%

/** * wb_memcg_offline - kill all wb's associated with a memcg being offlined * @memcg: memcg being offlined * * Also prevents creation of any new wb's associated with @memcg. */
void wb_memcg_offline(struct mem_cgroup *memcg) { LIST_HEAD(to_destroy); struct list_head *memcg_cgwb_list = mem_cgroup_cgwb_list(memcg); struct bdi_writeback *wb, *next; spin_lock_irq(&cgwb_lock); list_for_each_entry_safe(wb, next, memcg_cgwb_list, memcg_node) cgwb_kill(wb); memcg_cgwb_list->next = NULL; /* prevent new wb's */ spin_unlock_irq(&cgwb_lock); }

Contributors

PersonTokensPropCommitsCommitProp
tejun heotejun heo5277.61%150.00%
artem bityutskiyartem bityutskiy1522.39%150.00%
Total67100.00%2100.00%

/** * wb_blkcg_offline - kill all wb's associated with a blkcg being offlined * @blkcg: blkcg being offlined * * Also prevents creation of any new wb's associated with @blkcg. */
void wb_blkcg_offline(struct blkcg *blkcg) { LIST_HEAD(to_destroy); struct bdi_writeback *wb, *next; spin_lock_irq(&cgwb_lock); list_for_each_entry_safe(wb, next, &blkcg->cgwb_list, blkcg_node) cgwb_kill(wb); blkcg->cgwb_list.next = NULL; /* prevent new wb's */ spin_unlock_irq(&cgwb_lock); }

Contributors

PersonTokensPropCommitsCommitProp
tejun heotejun heo4169.49%125.00%
artem bityutskiyartem bityutskiy1220.34%125.00%
christoph hellwigchristoph hellwig46.78%125.00%
theodore tsotheodore tso23.39%125.00%
Total59100.00%4100.00%

#else /* CONFIG_CGROUP_WRITEBACK */
static int cgwb_bdi_init(struct backing_dev_info *bdi) { int err; bdi->wb_congested = kzalloc(sizeof(*bdi->wb_congested), GFP_KERNEL); if (!bdi->wb_congested) return -ENOMEM; err = wb_init(&bdi->wb, bdi, 1, GFP_KERNEL); if (err) { kfree(bdi->wb_congested); return err; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
tejun heotejun heo77100.00%2100.00%
Total77100.00%2100.00%


static void cgwb_bdi_destroy(struct backing_dev_info *bdi) { }

Contributors

PersonTokensPropCommitsCommitProp
tejun heotejun heo10100.00%1100.00%
Total10100.00%1100.00%

#endif /* CONFIG_CGROUP_WRITEBACK */
int bdi_init(struct backing_dev_info *bdi) { int ret; bdi->dev = NULL; bdi->min_ratio = 0; bdi->max_ratio = 100; bdi->max_prop_frac = FPROP_FRAC_BASE; INIT_LIST_HEAD(&bdi->bdi_list); INIT_LIST_HEAD(&bdi->wb_list); init_waitqueue_head(&bdi->wb_waitq); ret = cgwb_bdi_init(bdi); list_add_tail_rcu(&bdi->wb.bdi_node, &bdi->wb_list); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
tejun heotejun heo3844.19%440.00%
peter zijlstrapeter zijlstra3338.37%440.00%
jens axboejens axboe1416.28%110.00%
jan karajan kara11.16%110.00%
Total86100.00%10100.00%

EXPORT_SYMBOL(bdi_init);
int bdi_register(struct backing_dev_info *bdi, struct device *parent, const char *fmt, ...) { va_list args; struct device *dev; if (bdi->dev) /* The driver needs to use separate queues per device */ return 0; va_start(args, fmt); dev = device_create_vargs(bdi_class, parent, MKDEV(0, 0), bdi, fmt, args); va_end(args); if (IS_ERR(dev)) return PTR_ERR(dev); bdi->dev = dev; bdi_debug_register(bdi, dev_name(dev)); set_bit(WB_registered, &bdi->wb.state); spin_lock_bh(&bdi_lock); list_add_tail_rcu(&bdi->bdi_list, &bdi_list); spin_unlock_bh(&bdi_lock); trace_writeback_bdi_register(bdi); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
tejun heotejun heo9363.70%642.86%
peter zijlstrapeter zijlstra2114.38%214.29%
artem bityutskiyartem bityutskiy1812.33%17.14%
fengguang wufengguang wu106.85%321.43%
theodore tsotheodore tso21.37%17.14%
christoph hellwigchristoph hellwig21.37%17.14%
Total146100.00%14100.00%

EXPORT_SYMBOL(bdi_register);
int bdi_register_dev(struct backing_dev_info *bdi, dev_t dev) { return bdi_register(bdi, NULL, "%u:%u", MAJOR(dev), MINOR(dev)); }

Contributors

PersonTokensPropCommitsCommitProp
tejun heotejun heo2266.67%233.33%
peter zijlstrapeter zijlstra721.21%116.67%
neil brownneil brown26.06%116.67%
christoph hellwigchristoph hellwig13.03%116.67%
jens axboejens axboe13.03%116.67%
Total33100.00%6100.00%

EXPORT_SYMBOL(bdi_register_dev);
int bdi_register_owner(struct backing_dev_info *bdi, struct device *owner) { int rc; rc = bdi_register(bdi, NULL, "%u:%u", MAJOR(owner->devt), MINOR(owner->devt)); if (rc) return rc; bdi->owner = owner; get_device(owner); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
dan williamsdan williams64100.00%1100.00%
Total64100.00%1100.00%

EXPORT_SYMBOL(bdi_register_owner); /* * Remove bdi from bdi_list, and ensure that it is no longer visible */
static void bdi_remove_from_list(struct backing_dev_info *bdi) { spin_lock_bh(&bdi_lock); list_del_rcu(&bdi->bdi_list); spin_unlock_bh(&bdi_lock); synchronize_rcu_expedited(); }

Contributors

PersonTokensPropCommitsCommitProp
tejun heotejun heo2573.53%350.00%
jens axboejens axboe720.59%116.67%
christoph hellwigchristoph hellwig12.94%116.67%
artem bityutskiyartem bityutskiy12.94%116.67%
Total34100.00%6100.00%


void bdi_unregister(struct backing_dev_info *bdi) { /* make sure nobody finds us on the bdi_list anymore */ bdi_remove_from_list(bdi); wb_shutdown(&bdi->wb); cgwb_bdi_destroy(bdi); if (bdi->dev) { bdi_debug_unregister(bdi); device_unregister(bdi->dev); bdi->dev = NULL; } if (bdi->owner) { put_device(bdi->owner); bdi->owner = NULL; } }

Contributors

PersonTokensPropCommitsCommitProp
dan williamsdan williams2127.63%110.00%
christoph hellwigchristoph hellwig2026.32%220.00%
peter zijlstrapeter zijlstra1215.79%220.00%
jens axboejens axboe1215.79%110.00%
tejun heotejun heo810.53%330.00%
rabin vincentrabin vincent33.95%110.00%
Total76100.00%10100.00%


void bdi_exit(struct backing_dev_info *bdi) { WARN_ON_ONCE(bdi->dev); wb_exit(&bdi->wb); }

Contributors

PersonTokensPropCommitsCommitProp
tejun heotejun heo1872.00%360.00%
peter zijlstrapeter zijlstra728.00%240.00%
Total25100.00%5100.00%


void bdi_destroy(struct backing_dev_info *bdi) { bdi_unregister(bdi); bdi_exit(bdi); }

Contributors

PersonTokensPropCommitsCommitProp
tejun heotejun heo20100.00%1100.00%
Total20100.00%1100.00%

EXPORT_SYMBOL(bdi_destroy); /* * For use from filesystems to quickly init and register a bdi associated * with dirty writeback */
int bdi_setup_and_register(struct backing_dev_info *bdi, char *name) { int err; bdi->name = name; bdi->capabilities = 0; err = bdi_init(bdi); if (err) return err; err = bdi_register(bdi, NULL, "%.28s-%ld", name, atomic_long_inc_return(&bdi_seq)); if (err) { bdi_destroy(bdi); return err; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
jens axboejens axboe7594.94%133.33%
kees cookkees cook33.80%133.33%
christoph hellwigchristoph hellwig11.27%133.33%
Total79100.00%3100.00%

EXPORT_SYMBOL(bdi_setup_and_register); static wait_queue_head_t congestion_wqh[2] = { __WAIT_QUEUE_HEAD_INITIALIZER(congestion_wqh[0]), __WAIT_QUEUE_HEAD_INITIALIZER(congestion_wqh[1]) }; static atomic_t nr_wb_congested[2];
void clear_wb_congested(struct bdi_writeback_congested *congested, int sync) { wait_queue_head_t *wqh = &congestion_wqh[sync]; enum wb_congested_state bit; bit = sync ? WB_sync_congested : WB_async_congested; if (test_and_clear_bit(bit, &congested->state)) atomic_dec(&nr_wb_congested[sync]); smp_mb__after_atomic(); if (waitqueue_active(wqh)) wake_up(wqh); }

Contributors

PersonTokensPropCommitsCommitProp
andrew mortonandrew morton4563.38%112.50%
mel gormanmel gorman1115.49%112.50%
tejun heotejun heo1014.08%337.50%
jens axboejens axboe34.23%112.50%
xia kaixuxia kaixu11.41%112.50%
peter zijlstrapeter zijlstra11.41%112.50%
Total71100.00%8100.00%

EXPORT_SYMBOL(clear_wb_congested);
void set_wb_congested(struct bdi_writeback_congested *congested, int sync) { enum wb_congested_state bit; bit = sync ? WB_sync_congested : WB_async_congested; if (!test_and_set_bit(bit, &congested->state)) atomic_inc(&nr_wb_congested[sync]); }

Contributors

PersonTokensPropCommitsCommitProp
andrew mortonandrew morton2553.19%114.29%
mel gormanmel gorman1225.53%114.29%
tejun heotejun heo714.89%342.86%
jens axboejens axboe24.26%114.29%
xia kaixuxia kaixu12.13%114.29%
Total47100.00%7100.00%

EXPORT_SYMBOL(set_wb_congested); /** * congestion_wait - wait for a backing_dev to become uncongested * @sync: SYNC or ASYNC IO * @timeout: timeout in jiffies * * Waits for up to @timeout jiffies for a backing_dev (any backing_dev) to exit * write congestion. If no backing_devs are congested then just wait for the * next write to be completed. */
long congestion_wait(int sync, long timeout) { long ret; unsigned long start = jiffies; DEFINE_WAIT(wait); wait_queue_head_t *wqh = &congestion_wqh[sync]; prepare_to_wait(wqh, &wait, TASK_UNINTERRUPTIBLE); ret = io_schedule_timeout(timeout); finish_wait(wqh, &wait); trace_writeback_congestion_wait(jiffies_to_usecs(timeout), jiffies_to_usecs(jiffies - start)); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
andrew mortonandrew morton5570.51%133.33%
mel gormanmel gorman2126.92%133.33%
jens axboejens axboe22.56%133.33%
Total78100.00%3100.00%

EXPORT_SYMBOL(congestion_wait); /** * wait_iff_congested - Conditionally wait for a backing_dev to become uncongested or a pgdat to complete writes * @pgdat: A pgdat to check if it is heavily congested * @sync: SYNC or ASYNC IO * @timeout: timeout in jiffies * * In the event of a congested backing_dev (any backing_dev) and the given * @pgdat has experienced recent congestion, this waits for up to @timeout * jiffies for either a BDI to exit congestion of the given @sync queue * or a write to complete. * * In the absence of pgdat congestion, cond_resched() is called to yield * the processor if necessary but otherwise does not sleep. * * The return value is 0 if the sleep is for the full timeout. Otherwise, * it is the number of jiffies that were still remaining when the function * returned. return_value == timeout implies the function did not sleep. */
long wait_iff_congested(struct pglist_data *pgdat, int sync, long timeout) { long ret; unsigned long start = jiffies; DEFINE_WAIT(wait); wait_queue_head_t *wqh = &congestion_wqh[sync]; /* * If there is no congestion, or heavy congestion is not being * encountered in the current pgdat, yield if necessary instead * of sleeping on the congestion queue */ if (atomic_read(&nr_wb_congested[sync]) == 0 || !test_bit(PGDAT_CONGESTED, &pgdat->flags)) { cond_resched(); /* In case we scheduled, work out time remaining */ ret = timeout - (jiffies - start); if (ret < 0) ret = 0; goto out; } /* Sleep until uncongested or a write happens */ prepare_to_wait(wqh, &wait, TASK_UNINTERRUPTIBLE); ret = io_schedule_timeout(timeout); finish_wait(wqh, &wait); out: trace_writeback_wait_iff_congested(jiffies_to_usecs(timeout), jiffies_to_usecs(jiffies - start)); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
mel gormanmel gorman13495.71%250.00%
johannes weinerjohannes weiner53.57%125.00%
tejun heotejun heo10.71%125.00%
Total140100.00%4100.00%

EXPORT_SYMBOL(wait_iff_congested);
int pdflush_proc_obsolete(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { char kbuf[] = "0\n"; if (*ppos || *lenp < sizeof(kbuf)) { *lenp = 0; return 0; } if (copy_to_user(buffer, kbuf, sizeof(kbuf))) return -EFAULT; pr_warn_once("%s exported in /proc is scheduled for removal\n", table->procname); *lenp = 2; *ppos += *lenp; return 2; }

Contributors

PersonTokensPropCommitsCommitProp
wanpeng liwanpeng li8790.62%133.33%
chen gangchen gang88.33%133.33%
joe perchesjoe perches11.04%133.33%
Total96100.00%3100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
tejun heotejun heo219051.66%2428.57%
peter zijlstrapeter zijlstra4059.55%67.14%
jens axboejens axboe3057.20%910.71%
miklos szeredimiklos szeredi2987.03%11.19%
mel gormanmel gorman1934.55%44.76%
andrew mortonandrew morton1774.18%11.19%
artem bityutskiyartem bityutskiy1052.48%22.38%
dan williamsdan williams902.12%11.19%
wanpeng liwanpeng li872.05%11.19%
jan karajan kara641.51%55.95%
christoph hellwigchristoph hellwig561.32%44.76%
darrick j. wongdarrick j. wong521.23%11.19%
fengguang wufengguang wu511.20%67.14%
greg kroah-hartmangreg kroah-hartman330.78%11.19%
namjae jeonnamjae jeon310.73%11.19%
theodore tsotheodore tso290.68%11.19%
anton blanchardanton blanchard130.31%11.19%
joern engeljoern engel110.26%11.19%
johannes weinerjohannes weiner90.21%22.38%
chen gangchen gang80.19%11.19%
david chinnerdavid chinner70.17%11.19%
rabin vincentrabin vincent60.14%22.38%
dave chinnerdave chinner40.09%11.19%
neil brownneil brown40.09%11.19%
kees cookkees cook30.07%11.19%
david rientjesdavid rientjes30.07%11.19%
xia kaixuxia kaixu20.05%11.19%
joe perchesjoe perches10.02%11.19%
derek basehorederek basehore10.02%11.19%
rasmus villemoesrasmus villemoes10.02%11.19%
Total4239100.00%84100.00%
Directory: mm
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.