Linux核心程序詳解之三:flush-x:y
上一篇文章《裝置檔案與裝置號》當然不是突然穿插而來的自言自語,而是理解本文的前提,下面來看。是一類程序,這在系列的上一篇文章裡已經講到過,系統的絕大部分的bdi裝置都會有對應的flush-x:y核心程序,而這個x:y是對應bdi裝置的裝置號。
先看一下系統當前掛載的檔案系統:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
[[email protected] lenky]# cat /proc/mounts
rootfs / rootfs rw 0 0
/proc /proc proc rw,relatime 0 0 /sys /sys sysfs rw,seclabel,relatime 0 0
udev /dev devtmpfs rw,seclabel,relatime,size=502568k,nr_inodes=125642,mode=755 0 0
devpts /dev/pts devpts rw,seclabel,relatime,gid=5,mode=620,ptmxmode=000 0 0
tmpfs /dev/shm tmpfs rw,seclabel,relatime 0 0
/dev/mapper/VolGroup-lv_root / ext4 rw,seclabel,relatime,barrier=1,data=ordered 0 0 none /selinux selinuxfs rw,relatime 0 0
udev /dev devtmpfs rw,seclabel,relatime,size=502568k,nr_inodes=125642,mode=755 0 0
/proc/bus/usb /proc/bus/usb usbfs rw,relatime 0 0
/dev/sda1 /boot ext4 rw,seclabel,relatime,barrier=1,data=ordered 0 0
/dev/mapper/VolGroup-lv_home /home ext4 rw,seclabel,relatime,barrier=1,data=ordered 0 0 none /proc/sys/fs/binfmt_misc binfmt_misc rw,relatime 0 0
cgroup /cgroup/cpuset cgroup rw,relatime,cpuset 0 0
cgroup /cgroup/cpu cgroup rw,relatime,cpu 0 0
cgroup /cgroup/cpuacct cgroup rw,relatime,cpuacct 0 0
cgroup /cgroup/memory cgroup rw,relatime,memory 0 0
cgroup /cgroup/devices cgroup rw,relatime,devices 0 0
cgroup /cgroup/freezer cgroup rw,relatime,freezer 0 0
cgroup /cgroup/net_cls cgroup rw,relatime,net_cls 0 0
cgroup /cgroup/blkio cgroup rw,relatime,blkio 0 0
sunrpc /var/lib/nfs/rpc_pipefs rpc_pipefs rw,relatime 0 0
/etc/auto.misc /misc autofs rw,relatime,fd=7,pgrp=1393,timeout=300,minproto=5,maxproto=5,indirect 0 0
-hosts /net autofs rw,relatime,fd=13,pgrp=1393,timeout=300,minproto=5,maxproto=5,indirect 0 0
/dev/sdb1 /home/lenky/sdb/sdb1 ext4 rw,seclabel,relatime,barrier=1,data=ordered 0 0
/dev/sdc1 /home/lenky/sdc/sdc1 ext4 rw,seclabel,relatime,barrier=1,data=ordered 0 0
/dev/sdc2 /home/lenky/sdc/sdc2 ext4 rw,seclabel,relatime,barrier=1,data=ordered 0 0
[[email protected] lenky]#
|
注意需要關注的重點:
/dev/mapper/VolGroup-lv_root / ext4
/dev/mapper/VolGroup-lv_home /home ext4
/dev/sdb1 /home/lenky/sdb/sdb1 ext4
/dev/sdc1 /home/lenky/sdc/sdc1 ext4
/dev/sdc2 /home/lenky/sdc/sdc2 ext4
對應的裝置號分別為:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
[[email protected] lenky]# ls -l /dev/dm-*
brw-rw----. 1 root disk 253, 0 Jan 12 06:24 /dev/dm-0
brw-rw----. 1 root disk 253, 1 Jan 12 06:24 /dev/dm-1
brw-rw----. 1 root disk 253, 2 Jan 12 06:24 /dev/dm-2
[[email protected] lenky]#
[[email protected] lenky]# ls -l /dev/mapper/*
crw-rw----. 1 root root 10, 236 Jan 12 06:24 /dev/mapper/control
lrwxrwxrwx. 1 root root 7 Jan 12 06:24 /dev/mapper/VolGroup-lv_home -> ../dm-2
lrwxrwxrwx. 1 root root 7 Jan 12 06:24 /dev/mapper/VolGroup-lv_root -> ../dm-0
lrwxrwxrwx. 1 root root 7 Jan 12 06:24 /dev/mapper/VolGroup-lv_swap -> ../dm-1
[[email protected] lenky]#
[[email protected] lenky]# ls -l /dev/sda*
brw-rw----. 1 root disk 8, 0 Jan 12 06:24 /dev/sda
brw-rw----. 1 root disk 8, 1 Jan 12 06:24 /dev/sda1
brw-rw----. 1 root disk 8, 2 Jan 12 06:24 /dev/sda2
[[email protected] lenky]#
[[email protected] lenky]# ls -l /dev/sdb*
brw-rw----. 1 root disk 8, 16 Jan 12 06:25 /dev/sdb
brw-rw----. 1 root disk 8, 17 Jan 12 06:25 /dev/sdb1
[[email protected] lenky]#
[[email protected] lenky]# ls -l /dev/sdc*
brw-rw----. 1 root disk 8, 32 Jan 12 06:29 /dev/sdc
brw-rw----. 1 root disk 8, 33 Jan 12 06:39 /dev/sdc1
brw-rw----. 1 root disk 8, 34 Jan 12 06:29 /dev/sdc2
brw-rw----. 1 root disk 8, 35 Jan 12 06:29 /dev/sdc3
[[email protected] lenky]#
|
在任意時刻,我們能看到的flush-x:y核心程序並不固定,原因之前已經說過:
1 2 3 4 5 6 |
[[email protected] lenky]# ps aux | grep flush-
root 1250 0.0 0.0 0 0 ? S 06:24 0:00 [flush-253:0]
root 2180 0.0 0.0 0 0 ? S 06:39 0:00 [flush-253:2]
root 2186 2.0 0.0 0 0 ? S 06:39 0:07 [flush-8:32]
root 2329 0.0 0.0 103204 800 pts/3 S+ 06:45 0:00 grep flush-
[[email protected] lenky]#
|
呼叫sync命令,強制同步操作會建立所有對應的flush-x:y核心程序:
1 2 3 4 5 6 7 8 9 |
[[email protected] lenky]# sync
[[email protected] lenky]# ps aux | grep flush-
root 1250 0.0 0.0 0 0 ? S 06:24 0:00 [flush-253:0]
root 2180 0.0 0.0 0 0 ? S 06:39 0:00 [flush-253:2]
root 2186 2.0 0.0 0 0 ? S 06:39 0:07 [flush-8:32]
root 2331 0.0 0.0 0 0 ? S 06:45 0:00 [flush-8:0]
root 2332 0.0 0.0 0 0 ? S 06:45 0:00 [flush-8:16]
root 2334 0.0 0.0 103204 800 pts/3 S+ 06:45 0:00 grep flush-
[[email protected] lenky]#
|
可以看到flush-x:y核心程序是對應bdi整個裝置的,比如這裡的單個磁碟,而不是各個磁碟分割槽。
最後來看程式碼,flush-x:y核心程序的主體函式是bdi_writeback_thread(…):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
/*
* Handle writeback of dirty data for the device backed by this bdi. Also
* wakes up periodically and does kupdated style flushing.
*/
int
bdi_writeback_thread( void
*data)
{
struct
bdi_writeback *wb = data;
struct
backing_dev_info *bdi = wb->bdi;
long
pages_written;
current->flags |= PF_SWAPWRITE;
set_freezable();
wb->last_active = jiffies;
/*
* Our parent may run at a different priority, just set us to normal
*/
set_user_nice(current, 0);
trace_writeback_thread_start(bdi);
while
(!kthread_should_stop()) {
/*
* Remove own delayed wake-up timer, since we are already awake
* and we'll take care of the preriodic write-back.
*/
del_timer(&wb->wakeup_timer);
pages_written = wb_do_writeback(wb, 0);
trace_writeback_pages_written(pages_written);
if
(pages_written)
wb->last_active = jiffies;
set_current_state(TASK_INTERRUPTIBLE);
if
(!list_empty(&bdi->work_list) || kthread_should_stop()) {
__set_current_state(TASK_RUNNING);
continue ;
}
if
(wb_has_dirty_io(wb) && dirty_writeback_interval)
schedule_timeout(msecs_to_jiffies(dirty_writeback_interval * 10));
else
{
/*
* We have nothing to do, so can go sleep without any
* timeout and save power. When a work is queued or
* something is made dirty - we will be woken up.
*/
schedule();
}
try_to_freeze();
}
/* Flush any work that raced with us exiting */
if
(!list_empty(&bdi->work_list))
wb_do_writeback(wb, 1);
trace_writeback_thread_stop(bdi);
return
0;
}
|
函式主體是一個while迴圈,while語句呼叫一個判斷函式決定是否該結束迴圈:
1 2 3 4 5 6 7 8 9 10 11 12 |
/**
* kthread_should_stop - should this kthread return now?
*
* When someone calls kthread_stop() on your kthread, it will be woken
* and this will return true. You should then return, and your return
* value will be passed through to kthread_stop().
*/
int
kthread_should_stop( void )
{
return
to_kthread(current)->should_stop;
}
EXPORT_SYMBOL(kthread_should_stop);
|
而這個should_stop標記欄位會在bdi-default核心程序的KILL_THREAD動作裡進行修改(上一篇文章提到過),也就是通過這個欄位實現bdi-default核心程序對flush-x:y核心程序的控制:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
case
KILL_THREAD:
__set_current_state(TASK_RUNNING);
kthread_stop(task);
break ;
/**
* kthread_stop - stop a thread created by kthread_create().
* @k: thread created by kthread_create().
*
* Sets kthread_should_stop() for @k to return true, wakes it, and
* waits for it to exit. This can also be called after kthread_create()
* instead of calling wake_up_process(): the thread will exit without
* calling threadfn().
*
* If threadfn() may call do_exit() itself, the caller must ensure
* task_struct can't go away.
*
* Returns the result of threadfn(), or %-EINTR if wake_up_process()
* was never called.
*/
int
kthread_stop( struct
task_struct *k)
{
struct
kthread *kthread;
int
ret;
trace_sched_kthread_stop(k);
get_task_struct(k);
kthread = to_kthread(k);
barrier();
/* it might have exited */
if
(k->vfork_done != NULL) {
kthread->should_stop = 1;
wake_up_process(k);
wait_for_completion(&kthread->exited);
}
ret = k->exit_code;
put_task_struct(k);
trace_sched_kthread_stop_ret(ret);
return
ret;
}
EXPORT_SYMBOL(kthread_stop);
|
while迴圈內的工作,除去其它細節,值得關注的主要有三點:第一,修改最後活動時間(語句:wb->last_active = jiffies;),這樣bdi-default核心程序才能通過last_active這個欄位來判斷flush-x:y核心程序的活動狀態,如果很久沒有活動(比較的就是last_active欄位)則把它kill掉;第二,當然就是程序的主要工作,呼叫函式wb_do_writeback(…)進行同步操作;第三,如果在進行一次同步操作之後,又有新的髒資料需要同步,那麼先睡眠,等間隔時間(預設5秒)後超時醒來繼續工作;如果已經沒有髒資料需要同步,那麼直接schedule()排程其它程序,而程序本身進入可中斷睡眠狀態(注意前面的語句:set_current_state(TASK_INTERRUPTIBLE);),等待後續被喚醒繼續工作或被kill掉。
整個bdi-default和flush-x:y核心程序講完了,為什麼會有這樣的設計?在這裡有很好的說明:http://lwn.net/Articles/396757/,相比以前的多個pdflush間隔醒來,改進之後只需bdi-default一個核心程序間隔醒來就行了,這在電池供電裝置上明顯比較省電。
相關推薦
Linux核心程序詳解之三:flush-x:y
上一篇文章《裝置檔案與裝置號》當然不是突然穿插而來的自言自語,而是理解本文的前提,下面來看。是一類程序,這在系列的上一篇文章裡已經講到過,系統的絕大部分的bdi裝置都會有對應的flush-x:y核心程序,而這個x:y是對應bdi裝置的裝置號。 先看一下系統當前掛載的檔案系統
Linux核心程序詳解之一:sync_supers
先說下環境,CentOS 6.0/Linux kernel 2.6.38.8/X86-64,後面提到的程式碼也都來之kernel 2.6.38.8。這個環節下的程序列表具體如下所示,後續將有一系列的文章分析各個程序(主要是核心程序)的功能: [[email pro
OSPF詳解之三:OSPF LSA詳解
ospf lsa詳解 forwarding address OSPF LSA詳解OSPF V2版本中常用的主要有6類LSA,分別是Router-LSA、Network-LSA、Network-summary-LSA、ASBR-summary-LSA、AS-External-LSA、NSSA-LSA,接
大資料之hdfs詳解之三:put許可權剖析與常用命令
–無論是對於hdfs的讀和寫,對於使用者來說都是無感知的、透明的操作,使用者並不關心資料如何讀出來如何寫進去的,只要返回一個結果告訴使用者資料讀出來了或寫進去了,至於怎麼讀怎麼寫,使用者並不關心 補充: 讀:hdfs dfs -ls / = hdfs dfs
ORACLE PL/SQL程式設計詳解之三:PL/SQL流程控制語句(不給規則,不成方圓)
DECLARE v_first_name employees.first_name%TYPE; v_job_id employees.job_id%TYPE; v_salary employees.salary%TYPE; v_sal_raise NUMBER(3,2); B
Git詳解之三:Git分支
本篇blog為轉載,因為這是我看過關於git的最清晰易懂的blog教程,以備後用 Git 分支 幾乎每一種版本控制系統都以某種形式支援分支。使用分支意味著你可以從開發主線上分離開來,然後在不影響主線的同時繼續工作。在很多版本控制系統中,這是個昂貴的過程,常常需要建
第九課--09_01_磁盤及文件系統管理詳解之三
lock 多系統 otl rtx 塊大小 ble 當前 part 文件 一、VFS (Virtual File System)1: 用戶模式--用戶空間--用戶進程進程以模式的形式運行在的空間--用戶空間2:內核模式--內核空間3:block size : 1024-1k,
Linux下分割槽詳解之 Parted
通常我們用的比較多的一般都是fdisk工具來進行分割槽,但是現在由於磁碟越來越廉價,而且磁碟空間越來越大;而fdisk工具他對分割槽是有大小限制的,它只能劃分小於2T的磁碟。但是現在的磁碟空間很多都已經是遠遠大於2T了,甚至達到2.5T和3T,那要怎麼辦能,有兩個方法,其一是通過卷管理來實現
[轉]javaCV開發詳解之5:錄製音訊(錄製麥克風)到本地檔案/流媒體伺服器(基於javax.sound、javaCV-FFMPEG)
本文轉載自部落格:https://blog.csdn.net/eguid_1/article/details/52702385 ------------------------------------------------------------------------------------
ALSA音效卡驅動中的DAPM詳解之二:widget-具備路徑和電源管理資訊的kcontrol
上一篇文章中,我們介紹了音訊驅動中對基本控制單元的封裝:kcontrol。利用kcontrol,我們可以完成對音訊系統中的mixer,mux,音量控制,音效控制,以及各種開關量的控制,通過對各種kcontrol的控制,使得音訊硬體能夠按照我們預想的結果進行工作。同時我
ALSA音效卡驅動中的DAPM詳解之七:dapm事件機制(dapm event)
前面的六篇文章,我們已經討論了dapm關於動態電源管理的有關知識,包括widget的建立和初始化,widget之間的連線以及widget的上下電順序等等。本章我們準備討論dapm框架中的另一個機制:事件機制。通過dapm事件機制,widget可以對它所關心的dapm事
ALSA音效卡驅動中的DAPM詳解之五:建立widget之間的連線關係
前面我們主要著重於codec、platform、machine驅動程式中如何使用和建立dapm所需要的widget,route,這些是音訊驅動開發人員必須要了解的內容,經過前幾章的介紹,我們應該知道如何在alsa音訊驅動的3大部分(codec、platform、machin
Linux ALSA音效卡驅動之三:PCM裝置的建立
1. PCM是什麼 PCM是英文Pulse-code modulation的縮寫,中文譯名是脈衝編碼調製。我們知道在現實生活中,人耳聽到的聲音是模擬訊號,PCM就是要把聲音從模擬轉換成數字訊號的一種技術,他的原理簡單地說就是利用一個固定的頻率對模擬訊號進行取
linux核心sysfs詳解-1
sysfs 是 Linux 核心中設計較新的一種虛擬的基於記憶體的檔案系統,它的作用與 proc 有些類似,但除了與 proc 相同的具有檢視和設定核心引數功能之外,還有為 Linux 統一裝置模型作為管理之用。相比於 proc 檔案系統,使用 sysfs 匯出核心資料的方
Oracle記憶體詳解之三 Shared pool 共享池
一. Shared Pool 概述 在之前的blog對Oracle 的記憶體架構也做了一個概述,參考: 在網上搜到一篇介紹shared pool 非常詳細的pdf資料。 原文連結以找不到,但還是要感謝作者Kamus的辛勤
Linux下分割槽詳解之--Fdisk
Linux下分割槽詳解之--Fdisk 作者:吳偉龍 1、 通過Fdisk檢視系統分割槽詳細資訊: Fdisk –l 詳解: [[email protected]
UIView詳解之十:控制元件改變座標系(convertRect:)
一、示例 如下圖所示,橙色view是藍色view的子控制元件,藍色view是綠色view的子控制元件。由於橙色view的frame是參考藍色view的,因此,如果需要獲取橙色view相對於綠色view的位置,就必須進行座標系的轉換。 二、實現方法 UIView類中提供瞭如下四個方法,可以改變座標系
javaCV開發詳解之4:轉流器實現(也可作為本地收流器、推流器,新增新增圖片及文字水印,視訊影象幀儲存),實現rtsp/rtmp/本地檔案轉發到rtmp流媒體伺服器(基於javaCV-FFMPEG)
javaCV系列文章: 補充篇: 歡迎大家積極開心的加入討論群 javacpp-ffmpeg: 前言: 本章基於javaCV實現轉流器和收流器功能,測試採用監控rtsp地址轉發至rtmp伺服器地址 新增openCV儲存圖片功能。 補充:
Linux核心編譯詳解
學習了網上的一些資料,自己試著摸索了一下,整理出此文。 由於在下水平相當有限,不當之處,還望大家批評指正^_^ 重要的參考資料有: 好了,下面進入正題。 一、準備工作 準備工作如何做,這裡就不詳說了。 a) 首先,你要有一臺PC(這不廢話麼^_^),裝好了Lin
javaCV開發詳解之2:推流器實現,推本地攝像頭視訊到流媒體伺服器以及攝像頭錄製視訊功能實現(基於javaCV-FFMPEG、javaCV-openCV)
javaCV系列文章: 補充篇: 歡迎大家積極開心的加入討論群 javacpp-ffmpeg: 前言: 本章將在上一章的基礎上,增加視訊推流到流媒體伺服器和視訊錄製的功能; 功能:實現邊播放邊錄製/推流,停止預覽即停止錄製/推流 提示: