前文对pdflush的基本概念和使用方法做了简单的介绍,下面将详细介绍pdflush在Linux内核中的实现,本文的分析基于2.6.10内核。
基本调用流程
如下图为pdflush的基本调用流程,在模块初始化的时候会启动一个pdflush线程,__pdflush()函数为线程函数,具体工作在该函数中完成。
线程池
如下为该函数的具体实现,该函数实际上实现了一个线程池的功能,具体工作由pdflu_work关联的函数完成:
static int __pdflush(struct pdflush_work *my_work)
{
current->flags |= PF_FLUSHER;
my_work->fn = NULL;
my_work->who = current;
INIT_LIST_HEAD(&my_work->list); //链表项初始化
spin_lock_irq(&pdflush_lock);
nr_pdflush_threads++; //线程计数
for ( ; ; ) {
struct pdflush_work *pdf;
set_current_state(TASK_INTERRUPTIBLE);
list_move(&my_work->list, &pdflush_list);
my_work->when_i_went_to_sleep = jiffies;
spin_unlock_irq(&pdflush_lock);
schedule(); //将自己调度出去
if (current->flags & PF_FREEZE) {
refrigerator(PF_FREEZE);
spin_lock_irq(&pdflush_lock);
continue;
}
spin_lock_irq(&pdflush_lock);
if (!list_empty(&my_work->list)) {
printk("pdflush: bogus wakeup!\n");
my_work->fn = NULL;
continue;
}
if (my_work->fn == NULL) {
printk("pdflush: NULL work function\n");
continue;
}
spin_unlock_irq(&pdflush_lock);
(*my_work->fn)(my_work->arg0); //具体的刷写函数,由pdflush_operation函数指定
/*
* Thread creation: For how long have there been zero
* available threads?
*/
if (jiffies - last_empty_jifs > 1 * HZ) {
/* unlocked list_empty() test is OK here */
if (list_empty(&pdflush_list)) {
/* unlocked test is OK here */
if (nr_pdflush_threads < MAX_PDFLUSH_THREADS)
start_one_pdflush_thread();
}
}
spin_lock_irq(&pdflush_lock);
my_work->fn = NULL;
/*
* Thread destruction: For how long has the sleepiest
* thread slept?
*/
if (list_empty(&pdflush_list))
continue;
if (nr_pdflush_threads <= MIN_PDFLUSH_THREADS)
continue;
pdf = list_entry(pdflush_list.prev, struct pdflush_work, list);
if (jiffies - pdf->when_i_went_to_sleep > 1 * HZ) {
/* Limit exit rate */
pdf->when_i_went_to_sleep = jiffies;
break; /* exeunt */
}
}
nr_pdflush_threads--;
spin_unlock_irq(&pdflush_lock);
return 0;
}
struct pdflush_work {
struct task_struct *who; /* 具体线程 */
void (*fn)(unsigned long); /* A callback function */
unsigned long arg0; /* An argument to the callback */
struct list_head list; /* On pdflush_list, when idle */
unsigned long when_i_went_to_sleep;
};
int pdflush_operation(void (*fn)(unsigned long), unsigned long arg0)
{
unsigned long flags;
int ret = 0;
if (fn == NULL)
BUG(); /* fn是具体的刷写处理函数,如果要唤醒线程池,该函数自然不能为空 */
spin_lock_irqsave(&pdflush_lock, flags);
if (list_empty(&pdflush_list)) {
spin_unlock_irqrestore(&pdflush_lock, flags);
ret = -1;
} else {
struct pdflush_work *pdf;
pdf = list_entry(pdflush_list.next, struct pdflush_work, list); //从pdflush链表中取出一项
list_del_init(&pdf->list);
if (list_empty(&pdflush_list))
last_empty_jifs = jiffies;
pdf->fn = fn;
pdf->arg0 = arg0; //初始化具体的刷洗函数和参数,唤醒线程池进行刷洗
wake_up_process(pdf->who);
spin_unlock_irqrestore(&pdflush_lock, flags);
}
return ret;
}