歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> Linux技術

Linux那些事兒之我是Sysfs(10)sysfs 創建目錄

每當我們新增一個kobject結構的時候,同時會在/sys下創建一個目錄。
kobject_add() -> create_dir() -> sysfs_create_dir()
此時,我還想重申,kernel代碼的更新換代是很快的,我們的目的是懂得代碼背後的原理,知識,或曰哲學。我不想講的太細,因為關於sysfs的部分從2.6.10到現在2.6.22已經改了很多了。但其總體架構沒變。寫此文的目的是讓您跟著我的思路走一遍,對sysfs有了一個總體上的認識。然後自己就可以去看最新的代碼了。最新的代碼肯定是效率更高,條理邏輯更清晰。
sysfs_create_dir()流程圖如下:
-> create_dir()
-> *d = sysfs_get_dentry()
-> lookup_hash()
-> __lookup_hash()
-> cached_lookup()
-> new = d_alloc(base, name);
-> inode->i_op->lookup(inode, new, nd)
-> sysfs_create(*d, mode, init_dir)
-> sysfs_new_inode(mode)
-> init_dir(inode); // Call back function
-> sysfs_make_dirent()
-> sysfs_new_dirent()
-> dentry->d_fsdata = sysfs_get(sd);
-> dentry->d_op = &sysfs_dentry_ops;
-> (*d)->d_op = &sysfs_dentry_ops;
135 int sysfs_create_dir(struct kobject * kobj)
136 {
137 struct dentry * dentry = NULL;
138 struct dentry * parent;
139 int error = 0;
140
141 BUG_ON(!kobj);
142
143 if (kobj->parent)
144 parent = kobj->parent->dentry;
145 else if (sysfs_mount && sysfs_mount->mnt_sb)
146 parent = sysfs_mount->mnt_sb->s_root;
147 else
148 return -EFAULT;
149
150 error = create_dir(kobj,parent,kobject_name(kobj),&dentry);
151 if (!error)
152 kobj->dentry = dentry;
153 return error;
154 }
143-148就是找到父輩的kobject,再調用create_dir();
95 static int create_dir(struct kobject * k, struct dentry * p,
96 const char * n, struct dentry ** d)
97 {
98 int error;
99 umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;
100
101 down(&p->d_inode->i_sem);
102 *d = sysfs_get_dentry(p,n);
103 if (!IS_ERR(*d)) {
104 error = sysfs_create(*d, mode, init_dir);
105 if (!error) {
106 error = sysfs_make_dirent(p->d_fsdata, *d, k, mode,
107 SYSFS_DIR);
108 if (!error) {
109 p->d_inode->i_nlink++;
110 (*d)->d_op = &sysfs_dentry_ops;
111 d_rehash(*d);
112 }
113 }
114 if (error && (error != -EEXIST))
115 d_drop(*d);
116 dput(*d);
117 } else
118 error = PTR_ERR(*d);
119 up(&p->d_inode->i_sem);
120 return error;
121 }
99行,設置‘文件’ 屬性,101獲取信號量。
(1)sysfs_get_dentry()
102行sysfs_get_dentry()。它的作用是根據父輩dentry和文件名得到dentry結構。首先在緩存中找,如果找到就返回,找不到就用d_alloc()新建一個dentry結構。我們是新建文件夾,緩存中自然是沒有的,所以要用d_alloc()來新建一個。接著我們調用lookup函數,它定義如下。
struct inode_operations sysfs_dir_inode_operations = {
.lookup = sysfs_lookup,
};
204 static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
205 struct nameidata *nd)
206 {
207 struct sysfs_dirent * parent_sd = dentry->d_parent->d_fsdata;
208 struct sysfs_dirent * sd;
209 int err = 0;
210
211 list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
212 if (sd->s_type & SYSFS_NOT_PINNED) {
213 const unsigned char * name = sysfs_get_name(sd);
214
215 if (strcmp(name, dentry->d_name.name))
216 continue;
217
218 if (sd->s_type & SYSFS_KOBJ_LINK)
219 err = sysfs_attach_link(sd, dentry);
220 else
221 err = sysfs_attach_attr(sd, dentry);
222 break;
223 }
224 }
225
226 return ERR_PTR(err);
227 }
前面講過lookup函數的作用。它在inode代表的文件夾下查找有沒有名為dentry.d name.name的文件。如果有,就將其對應的inode結構從信息的載體中讀出來。由於是新建的文件夾,所以lookup函數在我們這個故事裡根本沒做事。但是我還是忍不住想分析一下lookup函數。
sysfs文件系統中,文件夾的inode和dentry結構一直都是存在於內存中的,所以不用再進行讀取了。而文件,鏈接的inode事先是沒有的,需要從載體中讀出。這就是212行這個判斷的作用。可以看出,如果是文件夾,循環裡面啥都沒做。
#define SYSFS_NOT_PINNED /
(SYSFS_KOBJ_ATTR | SYSFS_KOBJ_BIN_ATTR | SYSFS_KOBJ_LINK)
但是sysfs的lookup還有它不同之處。其他文件系統像ext3格式中普通文件的inode,在文件創建之時就已經創建了。但是,sysfs不一樣,它在創建普通文件時,只是先創建一個sysfs_dirent結構。創建inode的工作是推遲到lookup函數來完成的。在下一節sysfs_create_file()會看到這一點。
sysfs_attach_attr()和sysfs_attach_link()的作用就是根據dentry和sysfs_dirent新建一個inode。
總之,我們通過sysfs_get_dentry()得到了一個新建的dentry結構。
(2)sysfs_create()分析 (104行)
sysfs_create()->sysfs_new_inode(mode) -> new_inode(sysfs_sb)
創建一個新的索引節點inode。sysfs_sb是sysfs的超級塊(super_block)結構。mode則是inode的屬性,它記錄了如下信息,比如,文件類型(是文件夾,鏈接,還是普通文件),inode的所有者,創建時間等等。
(3)sysfs make dirent()分析 (104行)
至此,我們得到了一個dirent結構,初始化,再把它連接到上層目錄的sysfs_dirent的s_children鏈表裡去。sysfs_make_dirent()為剛剛新建出來的dentry建立一個dirent結構。並將dentry和dirent聯系起來。
(4)總結
在sysfs下創建一個目錄,提供的函數是sysfs_create_dir()。創建了dentry, dirent, inode
結構, 它們之間的連接關系見圖1
Copyright © Linux教程網 All Rights Reserved