【轉(zhuǎn)】Linux那些事兒之我是Sysfs(12)舉例三:sysfs讀入文件夾內(nèi)容linux kernel 2009-07-14 16:33:26 閱讀77 評論0 字號:大中小 訂閱 上 回我們說到,如何創(chuàng)建文件夾和文件,。我們發(fā)現(xiàn),,在sysfs中,inode并不那么重要。這是因為我們所要讀寫的信息已經(jīng)就在內(nèi)存中,,并且已經(jīng)形成了層次結(jié)構(gòu),。我們只需有dentry,,就可以dentry->fsdata,就能找到我們讀些信息的來源 --- sysfs_dirent結(jié)構(gòu),。這也是我覺得有必要研究 sysfs的原因之一,,因為它簡單,而且不涉及具體的硬件驅(qū)動,,但是從這個過程中,,我們可以把文件系統(tǒng)中的一些基本數(shù)據(jù)結(jié)構(gòu)搞清楚。接下來,,我以讀取 sysfs文件和文件夾的內(nèi)容為例子,,講講文件讀的流程。那么關(guān)于寫,,還有關(guān)于symblink的東西完全可以以此類推了,。
我們新建文件夾時,設(shè)置了 struct file_operations sysfs_dir_operations = { 用一個簡短的程序來做實驗,。 #include<sys/types.h>
#include<dirent.h> #include<unistd.h> int main()...{ DIR * dir; struct dirent *ptr; dir = opendir("/sys/bus/"); while((ptr = readdir(dir))!=NULL)...{ printf("d_name :%s ",ptr->d_name); } closedir(dir); return -1; } 在用戶空間,,用gcc編譯執(zhí)行即可。我們來看看它究竟做了什么,。 (1)sysfs_dir_open() 這 是個用戶空間的程序,。opendir()是glibc的函數(shù),glibc也就是著名的標準c庫,。至于opendir ()是如何與sysfs dir open ()接上頭的,,那還得去看glibc的代碼。我就不想分析了...glibc可以從gnu的網(wǎng)站上自己下載源代碼,,編譯,。再用gdb調(diào)試,就可以看得跟清楚,。 static int sysfs_dir_open(struct inode *inode, struct file *file)
...{ struct dentry * dentry = file->f_dentry; struct sysfs_dirent * parent_sd = dentry->d_fsdata; down(&dentry->d_inode->i_sem); file->private_da up(&dentry->d_inode->i_sem); return file->private_da } 內(nèi)核空間:新建一個dirent結(jié)構(gòu),,連入父輩的dentry中,,并將它地址保存在file->private_da #define __dirstream DIR (2)sysfs_readdir() 流程如下:
readdir(dir)這個函數(shù)有點復(fù)雜,,雖然在main函數(shù)里的while循環(huán)中,,readdir被執(zhí)行了多次,我們看看glibc里面的代碼 readdir(dir)...{
...... if (dirp->offset >= dirp->size)...{ ...... getdents() ...... } ...... } 實 際上,,getdents() -> ... -> sysfs_readdir()只被調(diào)用了兩次,,getdents()一次就把所有的內(nèi)容都讀完,存在DIR結(jié)構(gòu)當中,,readdir()只是從DIR結(jié)構(gòu)當中每次取出一個,。DIR(dirstream)結(jié)構(gòu)就是一個流。而回調(diào)函數(shù)filldir的作用就是往這個流中填充數(shù)據(jù),。第二次調(diào)用getdents ()是用戶把DIR里面的內(nèi)容讀完了,,所以它又調(diào)用getdents()但是這次getdents()回返回NULL。 static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
...{ struct dentry *dentry = filp->f_dentry; struct sysfs_dirent * parent_sd = dentry->d_fsdata; struct sysfs_dirent *cursor = filp->private_da ino_t ino; int i = filp->f_pos; switch (i) ...{ case 0: ino = dentry->d_inode->i_ino; if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0) break; filp->f_pos++; i++; /**//* fallthrough */ case 1: ino = parent_ino(dentry); if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0) break; filp->f_pos++; i++; /**//* fallthrough */ default: if (filp->f_pos == 2) ...{ list_del(q); list_add(q, &parent_sd->s_children); } for (p=q->next; p!= &parent_sd->s_children; p=p->next) ...{ struct sysfs_dirent *next; const char * name; int len; next = list_entry(p, struct sysfs_dirent, s_sibling); if (!next->s_element) continue; name = sysfs_get_name(next); len = strlen(name); if (next->s_dentry) ino = next->s_dentry->d_inode->i_ino; else ino = iunique(sysfs_sb, 2); if (filldir(dirent, name, len, filp->f_pos, ino,dt_type(next)) < 0) return 0; list_del(q); list_add(q, p); p = q; filp->f_pos++; } } return 0; } 看sysfs_readdir ()其實很簡單,,它就是從我們調(diào)用sysfs_dir_open()時新建的一個sysfs_dirent結(jié)構(gòu)開始,,便利當前dentry-> dirent下的所有子sysfs_dirent結(jié)構(gòu)。讀出名字,,再回調(diào)函數(shù)filldir()將文件名,,文件類型等信息,按照一定的格式寫入某個緩沖區(qū),。 一個典型的filldir()就是filldir64(),,它的作用的按一定格式向緩沖區(qū)寫數(shù)據(jù),再把數(shù)據(jù)復(fù)制到用戶空間去,。 |
|