pdflush.c代码注释

  1 /*
  2  * mm/pdflush.c - worker threads for writing back filesystem data   3  *
  4  * Copyright (C) 2002, Linus Torvalds.
  5  *
  6  * 09Apr2002 Andrew Morton
  7  * Initial version
  8  * 29Feb2004 [email protected]
  9  * Move worker thread creation to kthread to avoid chewing
 10  * up stack space with nested calls to kernel_thread.
 11  */
 12 
 13 #include <linux/sched.h>
 14 #include <linux/list.h>
 15 #include <linux/signal.h>
 16 #include <linux/spinlock.h>
 17 #include <linux/gfp.h>
 18 #include <linux/init.h>
 19 #include <linux/module.h>
 20 #include <linux/fs.h>           /* Needed by writeback.h          */
 21 #include <linux/writeback.h>    /* Prototypes pdflush_operation() */
 22 #include <linux/kthread.h>
 23 #include <linux/cpuset.h>
 24 #include <linux/freezer.h>
 25 
 26 
 27 /*
 28  * Minimum and maximum number of pdflush instances
 29  */
 30 #define MIN_PDFLUSH_THREADS     2      //最少同时存在2个工作线程
 31 #define MAX_PDFLUSH_THREADS     8     //最多同时存在8个工作线程
 32 
 33 static void start_one_pdflush_thread(void);
 34 
 35 
 36 /*
 37  * The pdflush threads are worker threads for writing back dirty data.
 38  * Ideally, we'd like one thread per active disk spindle. But the disk
 39  * topology is very hard to divine at this level. Instead, we take
 40  * care in various places to prevent more than one pdflush thread from
 41  * performing writeback against a single filesystem. pdflush threads
 42  * have the PF_FLUSHER flag set in current->flags to aid in this.
 43  */
 44 
 45 /*
 46  * All the pdflush threads. Protected by pdflush_lock
 47  */
      //初始化pdflush线程描述符链表,用于保存正在睡眠的pdflush??
 48 static LIST_HEAD(pdflush_list);   
     //pdflush_lock用来保护链表不会被并发访问
 49 static DEFINE_SPINLOCK(pdflush_lock);
 50 
 51 /*
 52  * The count of currently-running pdflush threads. Protected
 53  * by pdflush_lock.
 54  *
 55  * Readable by sysctl, but not writable. Published to userspace at
 56  * /proc/sys/vm/nr_pdflush_threads.
 57  */
 58 int nr_pdflush_threads = 0;   //内核pdflush线程总数;
 59 
 60 /*
 61  * The time at which the pdflush thread pool last went empty
 62  */
 63 static unsigned long last_empty_jifs;   // 上次链表为空的时间;
 64 
 65 /*
 66  * The pdflush thread.
 67  *
 68  * Thread pool management algorithm:
 69  * 
 70  * - The minimum and maximum number of pdflush instances are bound
 71  * by MIN_PDFLUSH_THREADS and MAX_PDFLUSH_THREADS.
 72  * 
 73  * - If there have been no idle pdflush instances for 1 second, create
 74  * a new one.
 75  * 
 76  * - If the least-recently-went-to-sleep pdflush thread has been asleep
 77  * for more than one second, terminate a thread.
 78  */
 79 
 80 /*
 81  * A structure for passing work to a pdflush thread. Also for passing
 82  * state information between pdflush threads. Protected by pdflush_lock.
 83  */
 84 struct pdflush_work {
 85         struct task_struct *who;        /* The thread 指向线程描述符*/
 86         void (*fn)(unsigned long);      /* A callback function 负责脏页下盘回调函数的指针*/
 87         unsigned long arg0;             /* An argument to the callback 传给回调函数的参数*/
 88         struct list_head list;          /* On pdflush_list, when idle 链表的指针*/
 89         unsigned long when_i_went_to_sleep;  /* 该线程上次休眠的时间 */
 90 };
 91 
 92 static int __pdflush(struct pdflush_work *my_work)
 93 {
 94         current->flags |= PF_FLUSHER | PF_SWAPWRITE;
 95         set_freezable();         //置为可冻结状态
 96         my_work->fn = NULL;    //先将回调函数指针置为空
 97         my_work->who = current;   //将线程描述符置为当前线程的current指针
 98         INIT_LIST_HEAD(&my_work->list);    //初始化链表
 99 
100         spin_lock_irq(&pdflush_lock);   //加锁
101         for ( ; ; ) {
102                 struct pdflush_work *pdf;
103 
104                 set_current_state(TASK_INTERRUPTIBLE);    //将进程状态置为可中断
105                 list_move(&my_work->list, &pdflush_list);   //将该线程存入pdflush_list链表,准备睡眠
106                 my_work->when_i_went_to_sleep = jiffies;  //记录这次休眠的时间
107                 spin_unlock_irq(&pdflush_lock);   //解锁
108                 schedule();   //将cpu交给系统来调度
109                 try_to_freeze();  //检查是否要进入电源睡眠状态,并进行处理
110                 spin_lock_irq(&pdflush_lock);  //解锁
111                 if (!list_empty(&my_work->list)) {  //检查链表是否为空
112                         /*
113  * Someone woke us up, but without removing our control
114  * structure from the global list. swsusp will do this
115  * in try_to_freeze()->refrigerator(). Handle it.
116  */
117                         my_work->fn = NULL;  
118                         continue;
119                 }
120                 if (my_work->fn == NULL) {  //如果链表不为空,但回调函数为空,说明是假唤醒,需要继续循环
121                         printk("pdflush: bogus wakeup\n");
122                         continue;
123                 }
124                 spin_unlock_irq(&pdflush_lock);  //解锁
125 
126                 (*my_work->fn)(my_work->arg0);  //调用回调函数写脏页,干活就指着这里了
127 
128                 spin_lock_irq(&pdflush_lock);  //加锁
129 
130                 /*
131  * Thread creation: For how long have there been zero
132  * available threads?
133  *
134  * To throttle creation, we reset last_empty_jifs.
135  */
136                 if (time_after(jiffies, last_empty_jifs + 1 * HZ)) {  //如果当前的时间比上次链表为空时间晚1hz的时间
137                         if (list_empty(&pdflush_list)) {              //如果当前pdflush_list链表为空,说明当前的已经没有正在睡眠的pdflush线程
138                                 if (nr_pdflush_threads < MAX_PDFLUSH_THREADS) {    //如果当前的pdflush线程数小于8
139                                         last_empty_jifs = jiffies;   //更新上次链表为空时间
140                                         nr_pdflush_threads++;        //增加的线程数
141                                         spin_unlock_irq(&pdflush_lock);   //加锁pdflush_lock
142                                         start_one_pdflush_thread();    //启动新的pdflush线程
143                                         spin_lock_irq(&pdflush_lock);  //解锁pdflush_lock
144                                 }
145                         }
146                 }
147 
148                 my_work->fn = NULL;  //加下盘回调指针置空
149 
150                 /*
151  * Thread destruction: For how long has the sleepiest
152  * thread slept?
153  */
154                 if (list_empty(&pdflush_list))   //如果pdflush_list链表为空,说明没有pdflush线程睡眠,继续循环
155                         continue;
156                 if (nr_pdflush_threads <= MIN_PDFLUSH_THREADS)   //pdflush线程数小于最小pdflush线程数,继续循环
157                         continue;
158                 pdf = list_entry(pdflush_list.prev, struct pdflush_work, list);   //获得链表中,前一个pdflush指针
159                 if (time_after(jiffies, pdf->when_i_went_to_sleep + 1 * HZ)) {   //该线程是否已经休眠了1hz以上的时间
160                         /* Limit exit rate */
161                         pdf->when_i_went_to_sleep = jiffies;    //将当前的时间更新为休眠时间
162                         break;                                  /* exeunt */
163                 }
164         }
165         nr_pdflush_threads--;    //pdflush总数减一
166         spin_unlock_irq(&pdflush_lock);  //解锁pdflush_lock
167         return 0;
168 }
169 
170 /*
171  * Of course, my_work wants to be just a local in __pdflush(). It is
172  * separated out in this manner to hopefully prevent the compiler from
173  * performing unfortunate optimisations against the auto variables. Because
174  * these are visible to other tasks and CPUs. (No problem has actually
175  * been observed. This is just paranoia).
176  */
177 static int pdflush(void *dummy)
178 {
179         struct pdflush_work my_work;
180         cpumask_var_t cpus_allowed;
181 
182         /*
183  * Since the caller doesn't even check kthread_run() worked, let's not
184  * freak out too much if this fails.
185  */
186         if (!alloc_cpumask_var(&cpus_allowed, GFP_KERNEL)) {
187                 printk(KERN_WARNING "pdflush failed to allocate cpumask\n");
188                 return 0;
189         }
190 
191         /*
192  * pdflush can spend a lot of time doing encryption via dm-crypt. We
193  * don't want to do that at keventd's priority.
194  */
195         set_user_nice(current, 0);
196 
197         /*
198  * Some configs put our parent kthread in a limited cpuset,
199  * which kthread() overrides, forcing cpus_allowed == cpu_all_mask.
200  * Our needs are more modest - cut back to our cpusets cpus_allowed.
201  * This is needed as pdflush's are dynamically created and destroyed.
202  * The boottime pdflush's are easily placed w/o these 2 lines.
203  */
204         cpuset_cpus_allowed(current, cpus_allowed);
205         set_cpus_allowed_ptr(current, cpus_allowed);
206         free_cpumask_var(cpus_allowed);
207 
208         return __pdflush(&my_work);
209 }
210 
211 /*
212  * Attempt to wake up a pdflush thread, and get it to do some work for you.
213  * Returns zero if it indeed managed to find a worker thread, and passed your
214  * payload to it.
215  */
216 int pdflush_operation(void (*fn)(unsigned long), unsigned long arg0)  /* 用来尝试激活pdflush函数,用在writeback等需要回写脏页的函数中 */
217 {
218         unsigned long flags;
219         int ret = 0;
220 
221         BUG_ON(fn == NULL);     /* Hard to diagnose if it's deferred */
222 
223         spin_lock_irqsave(&pdflush_lock, flags);
224         if (list_empty(&pdflush_list)) {  //如果pdflush_list为空,说明pdflush内核线程已经够多了,不需要启动了
225                 ret = -1;
226         } else {
227                 struct pdflush_work *pdf;
228 
229                 pdf = list_entry(pdflush_list.next, struct pdflush_work, list);  /* 从pdflush休眠链表中取出一个pdflush线程指针 */
230                 list_del_init(&pdf->list);
231                 if (list_empty(&pdflush_list))  /* 如果这时候,pdflush休眠线程链表为空,则记录last_empty_jifs的时间 */
232                         last_empty_jifs = jiffies;
233                 pdf->fn = fn;    /* 为回写脏页的回调函数指针赋值 */
234                 pdf->arg0 = arg0;   /* 赋回调函数的参数 */
235                 wake_up_process(pdf->who);  /* 唤醒该pdflush内核线程 */
236         }
237         spin_unlock_irqrestore(&pdflush_lock, flags);
238 
239         return ret;
240 }
241 
242 static void start_one_pdflush_thread(void)   /* 用来启动一个新的pdflush线程 */
243 {
244         struct task_struct *k;
245 
246         k = kthread_run(pdflush, NULL, "pdflush");   /* 启动一个新的内核线程 */
247         if (unlikely(IS_ERR(k))) {                    /* 启动失败的异常处理 */
248                 spin_lock_irq(&pdflush_lock);
249                 nr_pdflush_threads--;
250                 spin_unlock_irq(&pdflush_lock);
251         }
252 }
253 
254 static int __init pdflush_init(void)       /* 初始化pdflush模块 */
255 {
256         int i;
257 
258         /*
259  * Pre-set nr_pdflush_threads... If we fail to create,
260  * the count will be decremented.
261  */
262         nr_pdflush_threads = MIN_PDFLUSH_THREADS;  /* 模块启动时,按照最少线程数启动pdflush内核线程 */
263 
264         for (i = 0; i < MIN_PDFLUSH_THREADS; i++)  /* 循环启动内核线程 */
265                 start_one_pdflush_thread();
266         return 0;
267 }
268 
269 module_init(pdflush_init);
270 


可以参考 http://liurugongzi.blog.sohu.com/155184332.html

你可能感兴趣的:(pdflush.c代码注释)