Chinaunix首页 | 论坛 | 博客
  • 博客访问: 677926
  • 博文数量: 64
  • 博客积分: 1470
  • 博客等级: 上尉
  • 技术积分: 2133
  • 用 户 组: 普通用户
  • 注册时间: 2009-08-18 12:08
个人简介

文章分类

全部博文(64)

文章存档

2013年(16)

2011年(4)

2010年(14)

2009年(30)

我的朋友

分类: LINUX

2013-04-07 15:11:06

一、前言
在linux2.6.32之前,linux下数据同步是基于pdflush线程机制来实现的,在linux2.6.32以上的版本,内核彻底删掉了pdflush机制,改为了基于per-bdi线程来实现数据同步,与pdflush线程相比,在per-bdi线程机制中,每个后备存储器拥有自己唯一的回写线程,数据同步时需要更少的线程、也不会有多个pdflush对同一个后备存储器进行回写的竞态问题,回写的效率更高。

二、初始化默认的后备存储器default_backing_dev_info
  1. static int __init default_bdi_init(void)
  2. {
  3.     int err;

  4.     /*创建同步每个后备存储器的超级块的线程*/
  5.     sync_supers_tsk = kthread_run(bdi_sync_supers, NULL, "sync_supers");
  6.     BUG_ON(IS_ERR(sync_supers_tsk));

  7.   /*初始化一个定时器,该定时器控制同步超级块的周期,每隔dirty_writeback_interval去唤醒一次sync_supers_tsk,从而同步超级块。
  8.     dirty_writeback_interval可以通过修改/proc/sys/vm/下的dirty_writeback_centisecs来修改,默认值是500,单位是10ms
  9.     定时器函数sync_supers_timer_fn用于唤醒同步超级块的线程sync_supers_tsk,并且更新定时器的到期时间,具体实现如下*/
  10.     setup_timer(&sync_supers_timer, sync_supers_timer_fn, 0);
  11.     /*用于更新定时器的到期时间,详见下面代码。*/
  12.     bdi_arm_supers_timer();

  13.     /*初始化default_backing_dev_info的成员变量,初始化相关的链表,相关的变量赋初值等操作,请读者自行阅读。*/
  14.     err = bdi_init(&default_backing_dev_info);
  15.     if (!err)
  16.       /*调用bdi_register注册默认的后备存储器default_backing_dev_infobdi_list链表,并创建默认的backing_dev_info管理线程,
  17.         用于管理其他的后备存储器的数据同步线程的创建和销毁,所有的后备存储器在初始化时都会调用bdi_register注册到bdi_list链表中。
  18.         bdi_register详见下文分析。*/
  19.         bdi_register(&default_backing_dev_info, NULL, "default");

  20.     /*初始化空的后备存储器,可以忽略。*/
  21.     err = bdi_init(&noop_backing_dev_info);

  22.     return err;
  23. }
sync_supers_timer_fn函数唤醒超级块数据同步线程,然后重设定时器。
  1. static void sync_supers_timer_fn(unsigned long unused)
  2. {
  3.     wake_up_process(sync_supers_tsk);
  4.     bdi_arm_supers_timer();
  5. }
bdi_arm_supers_timer函数重设定时器
  1. void bdi_arm_supers_timer(void)
  2. {
  3.     unsigned long next;

  4.     if (!dirty_writeback_interval)
  5.         return;

  6.     next = msecs_to_jiffies(dirty_writeback_interval * 10) + jiffies;
  7.     mod_timer(&sync_supers_timer, round_jiffies_up(next));
  8. }
三、bdi_register()函数分析
bdi_register函数用于注册后备存储器到全局链表bdi_list上,并且判断如果是默认的后备存储器default_backing_dev_info则创建bdi-default线程,用于管理创建或销毁所有后备存储器相关的同步回写线程
  1. int bdi_register(struct backing_dev_info *bdi, struct device *parent,
  2.         const char *fmt, ...)
  3. {
  4.     va_list args;
  5.     struct device *dev;

  6.     if (bdi->dev)    /* The driver needs to use separate queues per device */
  7.         return 0;

  8.     va_start(args, fmt);
  9.     dev = device_create_vargs(bdi_class, parent, MKDEV(0, 0), bdi, fmt, args);
  10.     va_end(args);
  11.     if (IS_ERR(dev))
  12.         return PTR_ERR(dev);

  13.     bdi->dev = dev;

  14.     /*
  15.      * Just start the forker thread for our default backing_dev_info,
  16.      * and add other bdi's to the list. They will get a thread created
  17.      * on-demand when they need it.
  18.      */
  19.     if (bdi_cap_flush_forker(bdi)) {
  20.         struct bdi_writeback *wb = &bdi->wb;

  21.         wb->task = kthread_run(bdi_forker_thread, wb, "bdi-%s",
  22.                         dev_name(dev));
  23.         if (IS_ERR(wb->task))
  24.             return PTR_ERR(wb->task);
  25.     }

  26.     bdi_debug_register(bdi, dev_name(dev));
  27.     set_bit(BDI_registered, &bdi->state);

  28.     spin_lock_bh(&bdi_lock);
  29.     list_add_tail_rcu(&bdi->bdi_list, &bdi_list);
  30.     spin_unlock_bh(&bdi_lock);

  31.     trace_writeback_bdi_register(bdi);
  32.     return 0;
  33. }







阅读(8658) | 评论(0) | 转发(2) |
给主人留下些什么吧!~~