http://blog.chinaunix.net/uid-9543173-id-3568434.html
一、前言
在linux2.6.32之前,linux下數據同步是基於pdflush線程機制來實現的,在linux2.6.32以上的版本,內核徹底刪掉了pdflush機制,改爲了基於per-bdi線程來實現數據同步,與pdflush線程相比,在per-bdi線程機制中,每個後備存儲器擁有自己唯一的回寫線程,數據同步時需要更少的線程、也不會有多個pdflush對同一個後備存儲器進行回寫的競態問題,回寫的效率更高。
二、初始化默認的後備存儲器default_backing_dev_info
- static
int __init default_bdi_init(void)
- {
- int err;
- /*創建同步每個後備存儲器的超級塊的線程*/
- sync_supers_tsk = kthread_run(bdi_sync_supers,
NULL,
"sync_supers");
- BUG_ON(IS_ERR(sync_supers_tsk));
- /*初始化一個定時器,該定時器控制同步超級塊的週期,每隔dirty_writeback_interval去喚醒一次sync_supers_tsk,從而同步超級塊。
- dirty_writeback_interval可以通過修改/proc/sys/vm/下的dirty_writeback_centisecs來修改,默認值是500,單位是10ms
- 定時器函數sync_supers_timer_fn用於喚醒同步超級塊的線程sync_supers_tsk,並且更新定時器的到期時間,具體實現如下*/
- setup_timer(&sync_supers_timer, sync_supers_timer_fn, 0);
- /*用於更新定時器的到期時間,詳見下面代碼。*/
- bdi_arm_supers_timer();
- /*初始化default_backing_dev_info的成員變量,初始化相關的鏈表,相關的變量賦初值等操作,請讀者自行閱讀。*/
- err = bdi_init(&default_backing_dev_info);
- if (!err)
- /*調用bdi_register註冊默認的後備存儲器default_backing_dev_info到bdi_list鏈表,並創建默認的backing_dev_info管理線程,
- 用於管理其他的後備存儲器的數據同步線程的創建和銷燬,所有的後備存儲器在初始化時都會調用bdi_register註冊到bdi_list鏈表中。
- bdi_register詳見下文分析。*/
- bdi_register(&default_backing_dev_info,
NULL,
"default");
- /*初始化空的後備存儲器,可以忽略。*/
- err = bdi_init(&noop_backing_dev_info);
- return err;
- }
- static
void sync_supers_timer_fn(unsigned
long unused)
- {
- wake_up_process(sync_supers_tsk);
- bdi_arm_supers_timer();
- }
- void bdi_arm_supers_timer(void)
- {
- unsigned long next;
- if (!dirty_writeback_interval)
- return;
- next = msecs_to_jiffies(dirty_writeback_interval
* 10)
+ jiffies;
- mod_timer(&sync_supers_timer, round_jiffies_up(next));
- }
bdi_register函數用於註冊後備存儲器到全局鏈表bdi_list上,並且判斷如果是默認的後備存儲器default_backing_dev_info則創建bdi-default線程,用於管理創建或銷燬所有後備存儲器相關的同步回寫線程。
- 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;
- /*
- * Just start the forker thread for our default backing_dev_info,
- * and add other bdi's to the list. They will get a thread created
- * on-demand when they need it.
- */
- if (bdi_cap_flush_forker(bdi))
{
- struct bdi_writeback
*wb = &bdi->wb;
- wb->task
= kthread_run(bdi_forker_thread, wb,
"bdi-%s",
- dev_name(dev));
- if (IS_ERR(wb->task))
- return PTR_ERR(wb->task);
- }
- bdi_debug_register(bdi, dev_name(dev));
- set_bit(BDI_registered,
&bdi->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;
- }