1. 程式人生 > >Linux核心程序詳解之三:flush-x:y

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

OSPFOSPF 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,接

大資料hdfsput許可權剖析與常用命令

–無論是對於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

GitGit分支

本篇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音效卡驅動中的DAPMwidget-具備路徑和電源管理資訊的kcontrol

上一篇文章中,我們介紹了音訊驅動中對基本控制單元的封裝:kcontrol。利用kcontrol,我們可以完成對音訊系統中的mixer,mux,音量控制,音效控制,以及各種開關量的控制,通過對各種kcontrol的控制,使得音訊硬體能夠按照我們預想的結果進行工作。同時我

ALSA音效卡驅動中的DAPMdapm事件機制(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: 前言: 本章將在上一章的基礎上,增加視訊推流到流媒體伺服器和視訊錄製的功能; 功能:實現邊播放邊錄製/推流,停止預覽即停止錄製/推流 提示: