日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux系统 proc self,Linux内核源代码情形分析-特殊文件系统/proc-对/proc/self/cwd的访问...

發布時間:2024/1/23 linux 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux系统 proc self,Linux内核源代码情形分析-特殊文件系统/proc-对/proc/self/cwd的访问... 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Linux內核源代碼情景分析-特殊文件系統/proc-對/proc/self/cwd的訪問

繼上篇文章Linux內核源代碼情景分析-特殊文件系統/proc,我們對/proc/loadavg訪問后,這篇文章是對/proc/self/cwd的訪問。

int __user_walk(const char *name, unsigned flags, struct nameidata *nd)

{

char *tmp;

int err;

tmp = getname(name);//在系統空間分配一個頁面,并從用戶空間把文件名復制到這個頁面

err = PTR_ERR(tmp);

if (!IS_ERR(tmp)) {

err = 0;

if (path_init(tmp, flags, nd))

err = path_walk(tmp, nd);

putname(tmp);

}

return err;

}? ? name就為/proc/self/cwd,重要分析下path_walk函數,請參考Linux內核源代碼情景分析-從路徑名到目標節點。

第一次循環path_walk發現/proc是個安裝節點而通過_follow_down找到了proc文件系統的根節點的dentry結構,nameidata結構中的指針dentry指向這個數據結構。、

第二次循環搜索路徑名中的下一個節點self,由于這個節點并不是路徑名的最后一個節點,所以執行的代碼如下:

dentry = cached_lookup(nd->dentry, &this, LOOKUP_CONTINUE);//在內存中尋找該節點業已建立的dentry結構

if (!dentry) {//如果沒有找到

dentry = real_lookup(nd->dentry, &this, LOOKUP_CONTINUE);//那么就要建立該節點的dentry結構

err = PTR_ERR(dentry);

if (IS_ERR(dentry))

break;

}? ? 參考Linux內核源代碼情景分析-特殊文件系統/proc,最終也要通過proc_root_lookup()調用proc_lookup(),試圖為節點建立起其dentry結構和inode結構。可是由于/proc/self并沒有一個固定的proc_dir_entry結構,所以對proc_lookup()的調用必然會失敗,因而會進一步調用proc_pid_lookup(),代碼如下:

static struct dentry *proc_root_lookup(struct inode * dir, struct dentry * dentry)

{

if (dir->i_ino == PROC_ROOT_INO) { /* check for safety... */

int nlink = proc_root.nlink;

nlink += nr_threads;

dir->i_nlink = nlink;

}

if (!proc_lookup(dir, dentry))///由于/proc/self并沒有一個固定的proc_dir_entry結構,所以對proc_lookup()的調用必然會失敗

return NULL;

return proc_pid_lookup(dir, dentry);//會調用這個函數

}struct dentry *proc_lookup(struct inode * dir, struct dentry *dentry)

{

struct inode *inode;

struct proc_dir_entry * de;

int error;

error = -ENOENT;

inode = NULL;

de = (struct proc_dir_entry *) dir->u.generic_ip;

if (de) {//找不到/proc/self節點

for (de = de->subdir; de ; de = de->next) {

if (!de || !de->low_ino)

continue;

if (de->namelen != dentry->d_name.len)

continue;

if (!memcmp(dentry->d_name.name, de->name, de->namelen)) {

int ino = de->low_ino;

error = -EINVAL;

inode = proc_get_inode(dir->i_sb, ino, de);

break;

}

}

}

if (inode) {

dentry->d_op = &proc_dentry_operations;

d_add(dentry, inode);

return NULL;

}

return ERR_PTR(error);//返回錯誤碼

}

struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry)

{

unsigned int pid, c;

struct task_struct *task;

const char *name;

struct inode *inode;

int len;

pid = 0;

name = dentry->d_name.name;

len = dentry->d_name.len;

if (len == 4 && !memcmp(name, "self", 4)) {//執行這里,name等于self

inode = new_inode(dir->i_sb);

if (!inode)

return ERR_PTR(-ENOMEM);

inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;

inode->i_ino = fake_ino(0, PROC_PID_INO);

inode->u.proc_i.file = NULL;

inode->u.proc_i.task = NULL;

inode->i_mode = S_IFLNK|S_IRWXUGO;

inode->i_uid = inode->i_gid = 0;

inode->i_size = 64;

inode->i_op = &proc_self_inode_operations;

d_add(dentry, inode);

return NULL;//返回了

}

while (len-- > 0) {

c = *name - '0';

name++;

if (c > 9)

goto out;

if (pid >= MAX_MULBY10)

goto out;

pid *= 10;

pid += c;

if (!pid)

goto out;

}

read_lock(&tasklist_lock);

task = find_task_by_pid(pid);

if (task)

get_task_struct(task);

read_unlock(&tasklist_lock);

if (!task)

goto out;

inode = proc_pid_make_inode(dir->i_sb, task, PROC_PID_INO);

free_task_struct(task);

if (!inode)

goto out;

inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO;

inode->i_op = &proc_base_inode_operations;

inode->i_fop = &proc_base_operations;

inode->i_nlink = 3;

inode->i_flags|=S_IMMUTABLE;

dentry->d_op = &pid_base_dentry_operations;

d_add(dentry, inode);

return NULL;

out:

return ERR_PTR(-ENOENT);

}? ? 其中proc_self_inode_operations結構定義如下:

static struct inode_operations proc_self_inode_operations = {

readlink:proc_self_readlink,

follow_link:proc_self_follow_link,

};? ? 還是第二輪循環,從proc_root_lookup返回到path_walk中以后,接著要檢查和處理兩件事,第一件是新找到的節點是否為安裝點;第二件就是它是否是一個連接節點。這正是我們在這里所關心的,因為/proc/self就是個連接節點。繼續看path_walk,代碼如下:

if (inode->i_op->follow_link) {//看看這個指針是否為NULL,這個指針是在ext2_read_inode中設置的

err = do_follow_link(dentry, nd);static inline int do_follow_link(struct dentry *dentry, struct nameidata *nd)//參數dentry為proc/self節點的dentry結構

{

int err;

if (current->link_count >= 8)

goto loop;

current->link_count++;

UPDATE_ATIME(dentry->d_inode);

err = dentry->d_inode->i_op->follow_link(dentry, nd);//proc_self_follow_link

current->link_count--;

return err;

loop:

path_release(nd);

return -ELOOP;

}? ??entry->d_inode->i_op->follow_link指向proc_self_follow_link,代碼如下:

static int proc_self_follow_link(struct dentry *dentry, struct nameidata *nd)

{

char tmp[30];

sprintf(tmp, "%d", current->pid);

return vfs_follow_link(nd,tmp);

}int vfs_follow_link(struct nameidata *nd, const char *link)

{

return __vfs_follow_link(nd, link);

}static inline int

__vfs_follow_link(struct nameidata *nd, const char *link)

{

int res = 0;

char *name;

if (IS_ERR(link))

goto fail;

if (*link == '/') {

path_release(nd);

if (!walk_init_root(link, nd))

/* weird __emul_prefix() stuff did it */

goto out;

}

res = path_walk(link, nd);

out:

if (current->link_count || res || nd->last_type!=LAST_NORM)

return res;

/*

* If it is an iterative symlinks resolution in open_namei() we

* have to copy the last component. And all that crap because of

* bloody create() on broken symlinks. Furrfu...

*/

name = __getname();

if (IS_ERR(name))

goto fail_name;

strcpy(name, nd->last.name);

nd->last.name = name;

return 0;

fail_name:

link = name;

fail:

path_release(nd);

return PTR_ERR(link);

}? ? 在__vfs_follow_link()中會調用path_walk()來尋找連接的目標節點,所以又會調用其父節點/proc的lookup函數,即proc_root_lookup(),不同的只是這次尋找的不是"self",而是當前進程的pid字符串。

struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry)

{

unsigned int pid, c;

struct task_struct *task;

const char *name;

struct inode *inode;

int len;

pid = 0;

name = dentry->d_name.name;

len = dentry->d_name.len;

if (len == 4 && !memcmp(name, "self", 4)) {//不執行這里,name不等于self

inode = new_inode(dir->i_sb);

if (!inode)

return ERR_PTR(-ENOMEM);

inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;

inode->i_ino = fake_ino(0, PROC_PID_INO);

inode->u.proc_i.file = NULL;

inode->u.proc_i.task = NULL;

inode->i_mode = S_IFLNK|S_IRWXUGO;

inode->i_uid = inode->i_gid = 0;

inode->i_size = 64;

inode->i_op = &proc_self_inode_operations;

d_add(dentry, inode);

return NULL;//返回了

}

while (len-- > 0) {//執行這里

c = *name - '0';

name++;

if (c > 9)

goto out;

if (pid >= MAX_MULBY10)

goto out;

pid *= 10;

pid += c;

if (!pid)

goto out;

}

read_lock(&tasklist_lock);

task = find_task_by_pid(pid);

if (task)

get_task_struct(task);

read_unlock(&tasklist_lock);

if (!task)

goto out;

inode = proc_pid_make_inode(dir->i_sb, task, PROC_PID_INO);

free_task_struct(task);

if (!inode)

goto out;

inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO;

inode->i_op = &proc_base_inode_operations;//注意這個指針,一會會用到

inode->i_fop = &proc_base_operations;

inode->i_nlink = 3;

inode->i_flags|=S_IMMUTABLE;

dentry->d_op = &pid_base_dentry_operations;

d_add(dentry, inode);

return NULL;

out:

return ERR_PTR(-ENOENT);

}

static struct inode_operations proc_base_inode_operations = {

lookup:proc_base_lookup,

};

proc_pid_make_inode,為進程創建一個inode結構static struct inode *proc_pid_make_inode(struct super_block * sb, struct task_struct *task, int ino)

{

struct inode * inode;

/* We need a new inode */

inode = new_inode(sb);

if (!inode)

goto out;

/* Common stuff */

inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;

inode->i_ino = fake_ino(task->pid, ino);

inode->u.proc_i.file = NULL;

/*

* grab the reference to task.

*/

inode->u.proc_i.task = task;//當前進程的task賦值到這里

get_task_struct(task);

if (!task->p_pptr)

goto out_unlock;

inode->i_uid = 0;

inode->i_gid = 0;

if (ino == PROC_PID_INO || task->dumpable) {

inode->i_uid = task->euid;

inode->i_gid = task->egid;

}

out:

return inode;

out_unlock:

iput(inode);

return NULL;

}

從path_walk返回后,nd->dentry已指向代表著當前進程的目錄節點的dentry結構,之后層層返回到proc_self_follow_link,最后返回到主path_walk的第二次循環中,開始執行第三次循環。

第三次循環,最后一個節點是"cwd",這一次所搜索的節點已經是路徑名中的最后一個節點,所以轉到last_component的地方,同樣也是在real_lookup()中通過父節點的inode_operations結構中的lookup函數指針執行實際的操作,也就是proc_base_lookup,代碼如下:

static struct dentry *proc_base_lookup(struct inode *dir, struct dentry *dentry)

{

struct inode *inode;

int error;

struct task_struct *task = dir->u.proc_i.task;//取出當前進程的task

struct pid_entry *p;

error = -ENOENT;

inode = NULL;

for (p = base_stuff; p->name; p++) {//在base_stuff中找到cwd,關于base_stuff如下面所示

if (p->len != dentry->d_name.len)

continue;

if (!memcmp(dentry->d_name.name, p->name, p->len))

break;

}

if (!p->name)

goto out;

error = -EINVAL;

inode = proc_pid_make_inode(dir->i_sb, task, p->type);//p->type為5

if (!inode)

goto out;

inode->i_mode = p->mode;

/*

* Yes, it does not scale. And it should not. Don't add

* new entries into /proc// without very good reasons.

*/

switch(p->type) {

case PROC_PID_FD:

inode->i_nlink = 2;

inode->i_op = &proc_fd_inode_operations;

inode->i_fop = &proc_fd_operations;

break;

case PROC_PID_EXE:

inode->i_op = &proc_pid_link_inode_operations;

inode->u.proc_i.op.proc_get_link = proc_exe_link;

break;

case PROC_PID_CWD:

inode->i_op = &proc_pid_link_inode_operations;//兩者很重要

inode->u.proc_i.op.proc_get_link = proc_cwd_link;//兩者很重要,inode->u.proc_i指向了proc_inode_info,結構如下面所示

break;

case PROC_PID_ROOT:

inode->i_op = &proc_pid_link_inode_operations;

inode->u.proc_i.op.proc_get_link = proc_root_link;

break;

case PROC_PID_ENVIRON:

inode->i_fop = &proc_info_file_operations;

inode->u.proc_i.op.proc_read = proc_pid_environ;

break;

case PROC_PID_STATUS:

inode->i_fop = &proc_info_file_operations;

inode->u.proc_i.op.proc_read = proc_pid_status;

break;

case PROC_PID_STAT:

inode->i_fop = &proc_info_file_operations;

inode->u.proc_i.op.proc_read = proc_pid_stat;

break;

case PROC_PID_CMDLINE:

inode->i_fop = &proc_info_file_operations;

inode->u.proc_i.op.proc_read = proc_pid_cmdline;

break;

case PROC_PID_STATM:

inode->i_fop = &proc_info_file_operations;

inode->u.proc_i.op.proc_read = proc_pid_statm;

break;

case PROC_PID_MAPS:

inode->i_fop = &proc_maps_operations;

break;

#ifdef CONFIG_SMP

case PROC_PID_CPU:

inode->i_fop = &proc_info_file_operations;

inode->u.proc_i.op.proc_read = proc_pid_cpu;

break;

#endif

case PROC_PID_MEM:

inode->i_op = &proc_mem_inode_operations;

inode->i_fop = &proc_mem_operations;

break;

default:

printk("procfs: impossible type (%d)",p->type);

iput(inode);

return ERR_PTR(-EINVAL);

}

dentry->d_op = &pid_dentry_operations;

d_add(dentry, inode);

return NULL;

out:

return ERR_PTR(error);

}struct pid_entry {

int type;

int len;

char *name;

mode_t mode;

};

enum pid_directory_inos {

PROC_PID_INO = 2,

PROC_PID_STATUS,

PROC_PID_MEM,

PROC_PID_CWD,

PROC_PID_ROOT,

PROC_PID_EXE,

PROC_PID_FD,

PROC_PID_ENVIRON,

PROC_PID_CMDLINE,

PROC_PID_STAT,

PROC_PID_STATM,

PROC_PID_MAPS,

PROC_PID_CPU,

PROC_PID_FD_DIR = 0x8000,/* 0x8000-0xffff */

};

#define E(type,name,mode) {(type),sizeof(name)-1,(name),(mode)}

static struct pid_entry base_stuff[] = {

E(PROC_PID_FD,"fd",S_IFDIR|S_IRUSR|S_IXUSR),

E(PROC_PID_ENVIRON,"environ",S_IFREG|S_IRUSR),

E(PROC_PID_STATUS,"status",S_IFREG|S_IRUGO),

E(PROC_PID_CMDLINE,"cmdline",S_IFREG|S_IRUGO),

E(PROC_PID_STAT,"stat",S_IFREG|S_IRUGO),

E(PROC_PID_STATM,"statm",S_IFREG|S_IRUGO),

#ifdef CONFIG_SMP

E(PROC_PID_CPU,"cpu",S_IFREG|S_IRUGO),

#endif

E(PROC_PID_MAPS,"maps",S_IFREG|S_IRUGO),

E(PROC_PID_MEM,"mem",S_IFREG|S_IRUSR|S_IWUSR),

E(PROC_PID_CWD,"cwd",S_IFLNK|S_IRWXUGO),

E(PROC_PID_ROOT,"root",S_IFLNK|S_IRWXUGO),

E(PROC_PID_EXE,"exe",S_IFLNK|S_IRWXUGO),

{0,0,NULL,0}

};

#undef Estruct proc_inode_info {

struct task_struct *task;

int type;

union {

int (*proc_get_link)(struct inode *, struct dentry **, struct vfsmount **);

int (*proc_read)(struct task_struct *task, char *page);

} op;

struct file *file;

};? ? 從proc_base_lookup()經由real_lookup()返回到path_walk時,返回值dentry已經指向了這個特定"cwd"節點dentry結構。但是接著同樣要受到對其Inode結構中的i_op指針以及相應inode_operations結構的指針follow_link的檢驗,看path_walk的代碼:

inode = dentry->d_inode;

if ((lookup_flags & LOOKUP_FOLLOW)//和第一次和第二次循環不同,必須LOOKUP_FOLLOW標志位置1

&& inode && inode->i_op && inode->i_op->follow_link) {

err = do_follow_link(dentry, nd);static inline int do_follow_link(struct dentry *dentry, struct nameidata *nd)

{

int err;

if (current->link_count >= 8)

goto loop;

current->link_count++;

UPDATE_ATIME(dentry->d_inode);

err = dentry->d_inode->i_op->follow_link(dentry, nd);

current->link_count--;

return err;

loop:

path_release(nd);

return -ELOOP;

}

dentry->d_inode->i_op指向了proc_pid_link_inode_operations結構,是在這里設置的:

case PROC_PID_CWD:

inode->i_op = &proc_pid_link_inode_operations;//兩者很重要

inode->u.proc_i.op.proc_get_link = proc_cwd_link;//兩者很重要,inode->u.proc_i指向了proc_inode_info結構static struct inode_operations proc_pid_link_inode_operations = {

readlink:proc_pid_readlink,

follow_link:proc_pid_follow_link

};? ? ?dentry->d_inode->i_op->follow_link(dentry, nd),proc_pid_follow_link(dentry, nd),也就是代碼如下:

static int proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd)//參數dentry為"cwd"節點dentry結構

{

struct inode *inode = dentry->d_inode;

int error = -EACCES;

/* We don't need a base pointer in the /proc filesystem */

path_release(nd);

if (current->fsuid != inode->i_uid && !capable(CAP_DAC_OVERRIDE))

goto out;

error = proc_check_root(inode);

if (error)

goto out;

error = inode->u.proc_i.op.proc_get_link(inode, &nd->dentry, &nd->mnt);//也就是proc_cwd_link

nd->last_type = LAST_BIND;

out:

return error;

}? ??inode->u.proc_i.op.proc_get_link(inode, &nd->dentry, &nd->mnt),也就是proc_cwd_link(inode, &nd->dentry, &nd->mnt),代碼如下:

static int proc_cwd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)

{

struct fs_struct *fs;

int result = -ENOENT;

task_lock(inode->u.proc_i.task);

fs = inode->u.proc_i.task->fs;//task指向相應進程的task_struct結構,進而可以得到這個進程的fs_struct結構

if(fs)

atomic_inc(&fs->count);

task_unlock(inode->u.proc_i.task);

if (fs) {

read_lock(&fs->lock);

*mnt = mntget(fs->pwdmnt);//nd->mnt指向了該目錄所在設備安裝時的vfsmount結構

*dentry = dget(fs->pwd);//nd->dentry指向了該進程的"當前工作目錄"的dentry結構

read_unlock(&fs->lock);

result = 0;

put_fs_struct(fs);

}

return result;

}? ? 當從proc_cwd_link()經由do_follow_link()返回到path_walk()中時,nameidata結構中指針已經指向最終的目標,即當前進程的當前工作目錄。

也就是:

int __user_walk(const char *name, unsigned flags, struct nameidata *nd)

{

char *tmp;

int err;

tmp = getname(name);//在系統空間分配一個頁面,并從用戶空間把文件名復制到這個頁面

err = PTR_ERR(tmp);

if (!IS_ERR(tmp)) {

err = 0;

if (path_init(tmp, flags, nd))

err = path_walk(tmp, nd);

putname(tmp);

}

return err;

}? ?此時nd->mnt指向了該目錄所在設備安裝時的vfsmount結構,nd->dentry指向了該進程的"當前工作目錄"的dentry結構。

總結

以上是生活随笔為你收集整理的Linux系统 proc self,Linux内核源代码情形分析-特殊文件系统/proc-对/proc/self/cwd的访问...的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。