Linux块设备子系统浅析(2.6.26)


这里只是说明每个函数大概是做些什么工作,用于了解块设备子系统工作的原理。

首先,系统初始化时,会调用sysinit_call()加载各个子系统,而对于块设备来说就是在,

Block/genhd.csubsys_initcall(genhd_device_init);

 

genhd_device_init主要做几件事情

 

  1. static int __init genhd_device_init(void)  
  2.   
  3. {  
  4.   
  5.          int error = class_register(&block_class);         …..  
  6.   
  7.          bdev_map = kobj_map_init(base_probe, &block_class_lock);  
  8.   
  9.          blk_dev_init();  
  10.  
  11.   
  12.  
  13. #ifndef CONFIG_SYSFS_DEPRECATED   
  14.   
  15.          /* create top-level block dir */  
  16.   
  17.          block_depr = kobject_create_and_add("block", NULL);  
  18.  
  19. #endif   
  20.   
  21.          return 0;  
  22.   
  23. }  

class_register(&block_class);///sys/class下创建block设备类

 

kobj_map_init(base_probe, &block_class_lock);中是创建一个kobject映射域,kobj_map是一个保存了一个255目索引,以主设备号为间隔的哈希表。主要的作用是当kobj_map调用时,会匹配设备,然后把设备主设备号写进哈希表里,然后调用它的base->get,初始化为base_probe

  1. static struct kobject *base_probe(dev_t devt, int *part, void *data)  
  2.   
  3. {  
  4.   
  5.          if (request_module("block-major-%d-%d", MAJOR(devt), MINOR(devt)) > 0)  
  6.   
  7.                    /* Make old-style 2.4 aliases work */  
  8.   
  9.                    request_module("block-major-%d", MAJOR(devt));  
  10.   
  11.          return NULL;  
  12.   
  13. }  

这函数的主要作用是加载内核模块。

 

kobject_create_and_add("block", NULL);sys下创建block目录

 

blk_dev_init();

 

  1. int __init blk_dev_init(void)  
  2.   
  3. {  
  4.   
  5.          int i;  
  6.   
  7.    
  8.   
  9.          kblockd_workqueue = create_workqueue("kblockd");  
  10.   
  11.          if (!kblockd_workqueue)  
  12.   
  13.                    panic("Failed to create kblockd/n");  
  14.   
  15.    
  16.   
  17.          request_cachep = kmem_cache_create("blkdev_requests",  
  18.   
  19.                             sizeof(struct request), 0, SLAB_PANIC, NULL);  
  20.   
  21.    
  22.   
  23.          blk_requestq_cachep = kmem_cache_create("blkdev_queue",  
  24.   
  25.                             sizeof(struct request_queue), 0, SLAB_PANIC, NULL);  
  26.   
  27.    
  28.   
  29.          for_each_possible_cpu(i)  
  30.   
  31.                    INIT_LIST_HEAD(&per_cpu(blk_cpu_done, i));  
  32.   
  33.    
  34.   
  35.          open_softirq(BLOCK_SOFTIRQ, blk_done_softirq, NULL);  
  36.   
  37.          register_hotcpu_notifier(&blk_cpu_notifier);  
  38.   
  39.    
  40.   
  41.          return 0;  
  42.   
  43. }  

kblockd_workqueue = create_workqueue("kblockd");这函数作用是创建一个工作队列和内核处理线程,这个工作队列会在申请请求时设定的超时处理函数blk_unplug_timeout里得到调用,目的是为是为是超时时调用kblockd_schedule_work(&q->unplug_work); q->unplug_work,这里的这个函数又是在blk_init_queue时指定的,可能很多不明白,但是这里为了说明这个工作队列的作用,不得不大概调出后面的调用顺序,这样更清晰,这里只要记住,这个工作队列是为了让要暂时阻塞不接受request,但又重新恢复接受时调用的。blk_plug_device()以及blk_remove_plug()

 

kmem_cache_create创建一些缓冲池,让一些请求或者请求队列在里面创建。

 

open_softirq(BLOCK_SOFTIRQ, blk_done_softirq, NULL);这个函数主要是初始化了一个软件中断,具体调用是在当处理请求完成后,调用raise_softirq_irqoff(BLOCK_SOFTIRQ);然后激活,进入blk_done_softirq,最后处理指定的函数完成完成处理命令。Xxx_ finish_command(cmd);

 

register_hotcpu_notifier(&blk_cpu_notifier);这个函数是为了让系统支持热插拔。 

  • 1
  • 2
  • 3
  • 下一页

相关内容