. The block layer entry function is Genhd_device_init (), which begins the analysis of the function:
function to implement the source code:
static int __init genhd_device_init (void)
{
Bdev_map = Kobj_map_init (Base_probe, &block_subsys_lock);
Blk_dev_init ();
Subsystem_register (&block_subsys);
return 0;
}
. Kobj_map_init
Related structure definition:
struct Kobj_map {
struct Probe {
struct probe *next;
dev_t Dev;
unsigned long range;
struct module *owner;
kobj_probe_t *get;
Int (*lock) (dev_t, void *);
void *data;
} *probes[255];
struct Mutex *lock;
};
function: Request a struct KOBJ_MAP structure object and complete initialization, here the member probes is a hash list, and the table index 0~254 corresponding to the index of the main device number, each hash list element corresponds to a registered master device number and this device number (that is, the corresponding device);
Initialization process: Request a struct probe the struct object base and assign the get member to the parameter base_probe, then assign the probes array to the Kobj_map object member to base (255 identical values);
static struct Kobject *base_probe (dev_t dev, int *part, void *data)
Base_probe function Description: Gets the range that owns the device number, view the source code the method actually does nothing but returns a null when the true meaning of the method is concerned with defining a format to be implemented in an overloaded manner;
. blk_dev_init
function to implement the source code:
int __init blk_dev_init (void)
{
int i;
Kblockd_workqueue = Create_workqueue ("KBLOCKD");
if (!kblockd_workqueue)
Panic ("Failed to create kblockd\n");
Request_cachep = Kmem_cache_create ("Blkdev_requests",
sizeof (struct request), 0, slab_panic, NULL, or NULL);
Requestq_cachep = Kmem_cache_create ("Blkdev_queue",
sizeof (request_queue_t), 0, slab_panic, NULL, NULL);
Iocontext_cachep = Kmem_cache_create ("Blkdev_ioc",
sizeof (struct io_context), 0, slab_panic, NULL, NULL);
FOR_EACH_POSSIBLE_CPU (i)
Init_list_head (&PER_CPU (Blk_cpu_done, i));
OPEN_SOFTIRQ (BLOCK_SOFTIRQ, BLK_DONE_SOFTIRQ, NULL);
Register_hotcpu_notifier (&blk_cpu_notifier);
BLK_MAX_LOW_PFN = MAX_LOW_PFN;
BLK_MAX_PFN = MAX_PFN;
return 0;
}
Create_workqueue: Assign work queues, one for each CPU;
Kmem_cache_create: Create a high buffer;
OPEN_SOFTIRQ: The BLOCK_SOFTIRQ type of soft interrupt is registered, while the activation interrupt is RAISE_SOFTIRQ or raise_softirq_irqoff;
The function that handles interrupts is BLK_DONE_SOFTIRQ:
function to implement the source code:
static void Blk_done_softirq (struct softirq_action *h)
{
struct List_head *cpu_list, local_list;
Local_irq_disable ();
Cpu_list = &__get_cpu_var (Blk_cpu_done);
List_replace_init (Cpu_list, &local_list);
Local_irq_enable ();
while (!list_empty (&local_list)) {
struct Request *rq = List_entry (local_list.next, struct request, donelist);
List_del_init (&rq->donelist);
RQ->Q->SOFTIRQ_DONE_FN (RQ);
}
}
The procedure is: first get the request terminal linked list, then get the request requests structure object, and then call the terminal handler function SOFTIRQ_DONE_FN, that is: request *rq->request_queue *q->softirq_done_ fn
Register_hotcpu_notifier: This function is relatively high-end and CPU hot-swap related, compile the kernel need to open the compiler switch CONFIG_HOTPLUG_CPU only valid;
BLK_MAX_LOW_PFN: Maximum physical frame number
BLK_MAX_PFN: The last usable page frame number in physical memory;
. subsystem_register
function to implement the source code:
int Subsystem_register (struct subsystem * s)
{
int error;
Subsystem_init (s);
Pr_debug ("Subsystem%s:registering\n", s->kset.kobj.name);
if (! ( Error = Kset_add (&s->kset))) {
if (!s->kset.subsys)
S->kset.subsys = s;
}
return error;
}
Here the main code is Kset_add, and Kset_add in other articles have been said here no longer explain;
Block layer of Linux kernel series (i)