2013年7月23日 星期二

[Linux] inode

 inode 译成中文就是索引节点。每个存储设备或存储设备的分区(存储设备是硬盘、软盘、U盘 ... ... )被格式化为文件系统后,应该有两部份,一部份是inode,另一部份是Block,Block是用来存储数据用的。而inode呢,就是用来存储这些数据的信息,这些信息包括文件大小、属主、归属的用户组、读写权限等。inode为每个文件进行信息索引,所以就有了inode的数值。操作系统根据指令,能通过inode值最快的找到相对应的文件。 
      做个比喻,比如一本书,存储设备或分区就相当于这本书,Block相当于书中的每一页,inode 就相当于这本书前面的目录,一本书有很多的内容,如果想查找某部份的内容,我们可以先查目录,通过目录能最快的找到我们想要看的内容。
      当我们用ls 查看某个目录或文件时,如果加上-i 参数,就可以看到inode节点了;比如ls -li lsfile.sh ,最前面的数值就是inode信息

用f2fs的實例來看,發現新的檔案建立後,並不會連續的使用inode節點。







Refs
[1] http://www.cnblogs.com/QJohnson/archive/2011/06/24/2089414.html

[Linux] kmem_cache

今天對於 f2fs 作GC時,宣告的第一個structure來做探討
static struct kmem_cache *winode_slab;
稍微追了一下winode_slab出現的地方。

先來介紹一下大神上搜到的資訊 在Refs[1]中提到:

在内核编程中,可能经常会有一些数据结构需要反复使用和释放,按照通常的思路,可能是使用kmallockfree来实现。
但是这种方式效率不高,Linux为我们提供了更加高效的方法——Slab高速缓存管理器
通过先使用kmem_cache_create函数创建一个高速缓存的头指针——在内核中是struct kmem_cache结构 (這不就是在f2fs裡面宣告的結構嗎!!),具体用法可以这样:
struct kmem_cache *cachep = NULL;
cachep = kmem_cache_create("cache_name", sizeof(struct yourstruct), 0, SLAB_HWCACHE_ALIGN, NULL, NULL);

 (應該可以在f2fs中也找到類似的東東!!)
果不其然~找到啦~

这样我们就获得了一个可用的cachep头指针。 (在f2fs的話就是 winode_slab啦)

当需要分配一个struct yourstruct的结构体空间时,我们只需要调用kmem_cache_alloc函数,就可以获得一个足够我们使用的空间的指针(为什么我要说足够呢?因为刚才的声明中我使用了一个标志——SLAB_HWCACHE_ALIGN,这个标志会让分配的空间对于硬件来说是对齐的,而不一定恰好等于sizeof(struct yourstruct)的结果)。范例代码如下:
struct yourstruct *bodyp = NULL;

bodyp = (struct yourstruct *) kmem_cache_alloc(cachep, GFP_ATOMIC & ~__GFP_DMA);

这样就可以使用bodyp指针所对应的空间存贮你需要的结构体信息了。
当用完结束后,我们需要释放空间,如何操作呢?代码很简单:
kmem_cache_free(cachep, bodyp);

在這邊我們注意到 f2fs中使用的flag 是 SLAB_RECLAIM_ACCOUNT 並非 SLAB_HWCACHE_ALIGN
 在Refs[2],[3]中提到: 
SLAB_RECLAIM_ACCOUNT:内核检查用户态程序有没有足够内存可用,被标记为这个标志的Slab将作为通缉对象。
SLAB_RECLAIM_ACCOUNT flag set, the page frames assigned to the slabs are accounted for as reclaimable pages when the kernel checks whether there is enough memory to satisfy some User Mode requests.


(應該可以在f2fs中也找到類似的東東!!)
果不其然~又找到啦~
  







ps. 若整個cache都不需要時,在f2fs中是call kmem_cache_destory~


kmem_cache_alloc()中第二個參數的探討,在Refs[4]中提到:

GFP_ATOMIC
用来从中断处理和进程上下文之外的其他代码中分配内存. 从不睡眠.
GFP_KERNEL
内核内存的正常分配. 可能睡眠.
GFP_USER
用来为用户空间页来分配内存; 它可能睡眠.
GFP_HIGHUSER
如同 GFP_USER, 但是从高端内存分配, 如果有. 高端内存在下一个子节描述.
GFP_NOIO
GFP_NOFS
这个标志功能如同 GFP_KERNEL, 但是它们增加限制到内核能做的来满足请求. 一个 GFP_NOFS 分配不允许进行任何文件系统调用, 而 GFP_NOIO 根本不允许任何 I/O 初始化. 它们主要地用在文件系统和虚拟内存代码, 那里允许一个分配睡眠, 但是递归的文件系统调用会是一个坏注意.
上面列出的这些分配标志可以是下列标志的相或来作为参数, 这些标志改变这些分配如何进行:
__GFP_DMA
这个标志要求分配在能够 DMA 的内存区. 确切的含义是平台依赖的并且在下面章节来解释.
__GFP_HIGHMEM
这个标志指示分配的内存可以位于高端内存.
__GFP_COLD
正常地, 内存分配器尽力返回"缓冲热"的页 -- 可能在处理器缓冲中找到的页. 相反, 这个标志请求一个"冷"页, 它在一段时间没被使用. 它对分配页作 DMA 读是有用的, 此时在处理器缓冲中出现是无用的. 一个完整的对如何分配 DMA 缓存的讨论看"直接内存存取"一节在第 1 章.
__GFP_NOWARN
这个很少用到的标志阻止内核来发出警告(使用 printk ), 当一个分配无法满足.
__GFP_HIGH
这个标志标识了一个高优先级请求, 它被允许来消耗甚至被内核保留给紧急状况的最后的内存页.
__GFP_REPEAT
__GFP_NOFAIL
__GFP_NORETRY
这些标志修改分配器如何动作, 当它有困难满足一个分配. __GFP_REPEAT 意思是" 更尽力些尝试" 通过重复尝试 -- 但是分配可能仍然失败. __GFP_NOFAIL 标志告诉分配器不要失败; 它尽最大努力来满足要求. 使用 __GFP_NOFAIL 是强烈不推荐的; 可能从不会有有效的理由在一个设备驱动中使用它. 最后, __GFP_NORETRY 告知分配器立即放弃如果得不到请求的内存.

Refs:
[1] http://blog.csdn.net/leolinux/article/details/6103712
[2] http://blog.csdn.net/tq02h2a/article/details/3628402
[3] http://linux.chinaunix.net/techdoc/net/2008/03/29/987845.shtml
[4] http://oss.org.cn/kernel-book/ldd3/ch08.html

2013年7月22日 星期一

[Linux] 使用Linux kernel的 tracepoint (trace_f2fs_iget)

今天繼續在trace f2fs source code GC的部分,參考j2ffs的文件中看到j2ffs 做GC時會call linux kernel的 iget(),就想到那 f2fs呢? 查詢後找到,f2fs_iget() -- trace_f2fs_iget() 一堆在/include/trace/events/裡面的東東。
DECLARE_EVENT_CLASS()、DEFINE_EVENT()、TRACE_EVENT()、TRACE_EVENT_CONDITION()於是開始了這篇紀錄....

在Ref[1]中提到,
Ø  追蹤點的目的
代码中的追踪点提供了在运行时调用探测函数的钩子。追踪点可以打开(已连接探测函数)或关闭(没有连接探测函数)。处于关闭状态的追踪点不会引发任何效果,除了增加了一点时间开销(检查一条分支语句的条件)和空间开销(在instrumented function[不知道如何翻译合适]的尾部增加几条函数调用的代码,在独立区域增加一个数据结构)。如果一个追踪点被打开,那么每次追踪点被执行时都会调用连接的探测函数,而且在调用者的执行上下文中。探测函数执行结束后,将返回到调用者(从追踪点继续执行)。
可以在代码中的重要位置安放追踪点。它们是轻量级的钩子函数,能够传递任意个数的参数,原型可以在定义追踪点的头文件中找到。
追蹤點可以用來進行系統追蹤並進行性能統計

在Ref[2]中提到,
2.3 钩子函数的执行
在要抓trace的地方,添加trace_##name,这样便可以调用我们注册的钩子函数。

因此知道trace_f2fs_iget()是要做啥了。

DEFINE_EVENT(f2fs__inode, f2fs_iget,

TP_PROTO(struct inode *inode),

TP_ARGS(inode)
);

#define TP_PROTO(args...) args
#define TP_ARGS(args...) args


Refs:
[1] http://blog.csdn.net/arethe/article/details/6293505
[2] http://blog.csdn.net/u011013137/article/details/9093823

2013年7月19日 星期五

[Linux] offsetof(TYPE, MEMBER)

offsetof(TYPE, MEMBER)
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER); 
分析:
========================================================================
(TYPE *)0, 將0強制轉型為TYPE型態指標,
p = (TYPE *)0, p是指向TYPE的指標, 值為0.
p->MEMBER就是MEMBER這個元素了, 而&(p->MEMBER)就是MEMBER的位址, 其base address是0, 如此一來就巧妙的轉化為TYPE中的偏移量. 再把結果強制轉換為size_t 就ok了, size_t 其實就是int.

typedef __kernel_size_t  size_t;
typedef unsigned int __kernel_size_t; 

可見 offsetof 的作用就是求出MEMBER在TYPE中的偏移量.

Reference: http://blog.csdn.net/sfrysh/article/details/5761148

[Linux] USB讀取速度測試

透過$ hdparm -Tt /dev/[device] 

實際操作截圖:


[Linux] Step by step compile Liunx Kernel for Add F2FS

Step by step compile Linux kernel for Add F2FS
(base on Ubuntu10.04& 3.10.0+ Kernel)

2013.7.9整理
編譯步驟:
1. http://www.kernel.org/ 上下載最新的内核source code: linux-2.6.35.2.tar.bz2(目前最新的版本),然後     放在/usr/src目錄下。
2. 為了使編譯過程方便,建議進入root帳戶進行操作,這樣做使你不用每次都用sudo命令。(原作者不太確     定這樣做安全性是否可靠)
    進入Termainal,執行: su root (我用這個才能進root: sudo -s) 然後輸入你的Password,這一就             在root帳戶權限下進行剩下的操作了。
3.下載的Linux source code是壓縮檔,需要解壓縮到目錄下: tar -j x vf linux-2.6.35.2.tar.bz2 -C                 /usr/src
4. 進入解壓後的目錄:cd /usr/src/linux-2.6.35.2
F2fs_1. 在你指定的目錄中(~/Desktop/f2fs/),下載3.10.0+kernel:
git clone git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs.git
F2fs_2.& 5. 檢查有無不正確的.o文件和依賴關係: make mrproper ( 其實這一部可以省略,因為是剛下載好的source code,一定是乾淨的;如果使用的是已經編譯過的code,則需要做這一步)
F2fs_2.& 6. 配置Kernel選項: make menuconfig (這一步很重要,它決定了你可以個人客製化你的Kernel。當你使用menuconfig時,會有一些選擇列出來) 主列表如下:
    General Setup 常規的配置,比如Kernel config, CPU GroupAduiting等等
    Loadable module support 客製化你要加載哪些modules
    Enable the block layer 主要是block設備和大文件的設置
    Processor type and features 處理器配置和特性
    Power management options 電源管理的客製化,比如Hibernate這種
    Bus options PCI總線的客製化
    Executable file formats 主要是設置ELF的配置
    Networking support 客製化網路選項,包括WirelessBluetoothNetwork選項
    Device Drivers 客製化你需要加載的設備驅動
    Fireware Drivers BIOSEFI這樣的固件驅動設置
    File System 文件系统的設置,包括EXT3, EXT4, FAT, CD/DVD...等等N
    Kernel hacking 主要是設置Kernel debugging的,做內核調試會有用
    Security options 安全選項
    Cryptographic API 加密設置,包括MD5, SHA1, CRC等等N種加密算法的配置
    Virtualization 虛擬化設置
    Library routines 主要客製CRC校驗的function
    上面是16大項,每一項都有n多小項,說真的這裡面每一項都夠研究一陣子的。不過對內核編譯而言,你可以全部採用默認選項(會延長編譯時間)。設置好了menuconfig,保存退出。
F2fs_3.&7. 建立Modules依賴關係: make dep
F2fs_4.&8. 刪除配置後剩下的不適用的文件:make clean
F2fs_5.&9. 編譯內核:make bzImage (這個會花些時間,看機器情況和menuconfig的定義而言。作者採用默認的設置,編譯時間花了20分鐘左右。如果kernel 小於512K,可以用make zImage命令)
F2fs_6.&10. 编譯内核模組:make modules (這個也會花點時間,要看你客製化的modules數量而言。採用默認設置,花了大約25分鐘。你可以用make –j<n> 加快編譯速度,n代表你CPU的數量)
F2fs_7.&11. 安裝內核模組:make modules_install
F2fs_8.&12. 安裝内核:make install
13. 創建initrd文件: (1) cd / (2) 輸入: mkinitramfs 2.6.35.2 -o /boot/initrd.img-2.6.35.2-generic
F2fs_9. 創建initrd文件: (1) cd / (2)輸入: mkinitramfs 3.10.0+ -o /boot/initrd.img-3.10.0+
14. 拷貝編譯好的內核image: cp /usr/src/linux-2.6.35.2/arch/i386/boot/bzImage /boot/vmlinuz-2.6.35.2-generic
F2fs_10. 拷貝編譯好的內核image: cp ~/Desktop/f2fs/f2fs/arch/i386/boot/bzImage /boot/vmlinuz-3.10.0+
F2fs_11.&.15. 最後一步,修改Grub,更新啟動列表: update-grub (如須手動編輯grub.cfg,則在root帳戶下使用gedit就可以了)
(注:Ubuntu10.04已經使用了Grub2來管理啟動設置,而不是Grub,所以在以往的/boot/grub路徑下你是找不到menu.lst, 因為Grub2已經使用了/boot/grub/grub.cfg來管理配置啟動設置,不過最好不要手動編譯這個文件,具體的方式是編輯/etc/default/grub/etc/grub.d下的腳本文件。有關Grub2的詳細教程,請參考https://docs.google.com/Doc?docid=0AeVQ5PqmbeaoZGc0czgyOWtfMjRjbWo0ODVoYw&hl=en )
F2fs_11.& 16. Reboot機器,然後Enjoy it!


實際執行截圖:
1.    格式化: mkfs.f2fs –l label /dev/sdb
2.    掛載: sudo mount –t f2fs /dev/sdb /mnt/f2fs

3.    Check設備是否完成掛載: df
4.    Check 設備file system type: df -T
5.    Menuconfig中和f2fs相關的選項



Reference: blog.csdn.ntw/zufeng_chen/article/details/5824544