权财,98,加勒比海盗4-雷竞技手机版_雷竞技手机版下载

频道:体育世界 日期: 浏览:183

这篇文章写的不错,给咱们进行共享

Linux体系是怎么区别一般文件与设备驱动文件的研讨一

文件的翻开

一般来说关于文件或许是设备的操作都是从open开端的,咱们首要要翻开这个设备节点或许是一般文件,才能够对这个文件进行read、write、ioctl、mmap等操作。所以一切的起源于open。咱们首要从open开端研讨。

在linux体系进程傍边,分为内核英姿带空间和用户空间。符艳朵当咱们在用户空间经过open之后,会发生一个软中止,然后经过体系调用堕入内核空间。经过体系调用号,咱们能够跳转到该中止例程的进口地址,咱们接着看内核源码的完结。

1、在arch/x86/include/asm/unis立可尿td_32.h中界说了体系调用号

#define __NR_restart_syscall 0

#define __NR_exit 1

#define __NR_f诗维蓝黛ork 2

#define __NR_read 3

#define __NR_write 4

#define __NR_open 5

#define __NR_close 6

#define __NR_waitpid 7

。。。。。。。。

2、当发生体系调用的时分,会进入到下面这个函数:

SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, int, mode)

{

long ret;

if (force_o_largefile())

flags |= O_LARGEFILE;

ret = do_sys_open(AT_FDCWD, filename, flags, mode);

/* avoid REGPARM breakage on x86: */

asmlinkage_protect(3, ret, filename, flags, mode);

return ret;

}

3、终究会调用到do_sys_open(),这个函数首要分配一个可用的文件描述符。而且经过调用do_filp_open()经过传进来的文件名查找到inode信息,而且依据这些信息创立一个file目标,而且将inode和file的联系相关起来。

long do_sys_open(int dfd, const char __user *filename, int flags, int mode)

{

/*获取文件称号,由getname()函数完结,其内部首要创立存取文件称号的空间,

然后*从用户空间把文件名复制过来*/

char *tmp = getname(filename);

int fd = PTR_ERR(tmp)毛球祖玛;

if (!IS_ERR(tmp)) {

/*获取一个可用的fd,此函数调用alloc_fd()函数从

fd_table中获取一个可用fd,并做些简略初始化,此函数内部完结比较简略,

此次剖析不细看,留意,关于文件描述符fd来讲,它只对本进程有用,

也即它只在该进程中可见而在其它进程中代表着彻底不同的文件。

*/

fd = get_unused_fd_flags(flags);

if (fd >= 0) {

/*fd获取成功则开端翻开文件,此函数是首要完结翻开功用的函数,在此先放一放,下面详细剖析*/

//假如分配fd成功,则创立一个file目标

struct file *f = do_filp_open(dfd, tmp, flags, mode, 0);

if (IS_ERR(f)) {

/*翻开失利,开释fd*/

put_unused_fd(fd);

fd = PTR_ERR(f);

} else {

/*文件假如现已被翻开了,调用fsnotify_open()函数,依据inode所指定的信息进行翻开

函数(参数为f)将该文件加入到文件监控的体系中。该体系是用来监控文件被翻开,创立,

读写,封闭,修正等操作的*/

fsnotify_open(f->f_path.dentry);

/*将文件指针安装在fd数组中

将struct file *f加入到fd索引方位处的数组中。假如后续进程中,有对该文件描述符的

操作的话,就会经过查找该数组得到对应的文件结构,然后在进行相关操作。*/

fd_install(fd, f);

}

}

/*开开释置从用户空间复制过来的文件名的存储空间*/

putname(tmp);

}

return fd;

}

4、do_filp_open函数的一个重要作用便是依据传递近来的权限进行剖析,而且剖析传递近来的途径姓名,依据途径名逐个解析成dentry,而且经过dentry找到inode,inode便是记录着该文件相关的信息, 包含文件的创立时刻和文件特点一切者等等信息,依据这些信息就能够找到对应的文件操作办法。在这个进程傍边有一个暂时的结构体用于保存在查找进程中的相关信息,便是

struct name两姐妹idata {

struct pathpath;//当时目录的dentry数据结构

struct qstrlast;//这个结构体也是暂时性的,首要用来保存当时目录的称号,杂凑值。

unsigned intflags;

intlast_type;

unsigneddepth;//衔接文件的深度(或许一个衔接文件跟到最终仍是一个了衔接文件)

//用来保存衔接文件的一些信息,下标表明衔接文件的深度

char *saved_names[MAX_NESTED_LINKS + 1];

/* Intent data */

union {

struct op鸿蒙天演诀en_intent open;

} intent;

};

struct file *do_filp_open(int dfd, const char *pathname,

int open_flag, int mode, int acc_mode)

{

/*当内核要拜访一个文件的时分,第一步要做的是找到这个文件,而查找文件的进程在vfs

里边是由path_lookup或许path_lookup_open函数来完结的。这两个函数将用户传进来的字符串表明的文件途径转换成一个dentry结构,并树立好相应的inode和file结构,将指向file

的描述符回来用户。用户随后经过文件描述符,来拜访这些数据结构当函数正确回来的时分,现已将inode和dentry的结构体创立好,而且绑定好*/

error = do_path_lookup(dfd, pathname, LOOKUP_PARENT, &nd);

/*

这个函数依据 struct nameidata 结构回来一个 struct file。能够看到

struct file 是在运用了 __dentry_open() 函数后被填充的,且运用的第

一个参数是 nameidata->dentry,这也是为什么咱们要取得 struct nameidata

的一个首要原因,其意图便是为了得到 struct dentry 结构。

在此刻,现已将inode和dentry的结构体创立好,而且绑定好*/

filp = nameidata_to_filp(&nd, open_flag);

mnt_drop_write(nd.path.mnt);

return filp;

}

struct file *do_filp_open(int dfd, const char *pathname,

int open_flag, int mode, int acc_mode)

{

...................

/*当内核要拜访一个文件的时分,第一步要做的是找到这个文件,而查找文件的进程在vfs

里边是由path_lookup或许path_lookup_open函数来完结的。这两个函数将用户传进来的字符串

表明的文件途径转换成一个dentry结构,并树立好相应的inode和file结构,将指向file

的描述符返亚洲热回用户。用户随后经过文件描述符,来拜访这些数据结构

当函数正确回来的时分,现已将inode和dentry的结构体创立好,而且绑定好*/

error = do_path_lookup(dfd, pathname, LOOKUP_PARENT, &nd);

/*

这个函数依据 struct nameidata 结构回来一个 struct file。能够看到

struct file 是在运用了 __dentry_open() 函数后被填充的,且运用的第

一个参数是 nameidata->dentry,这也是为什么咱们要取得 struct nameidata

的一个首要原因,其意图便是为了得到 struct dentry 结构。

在此刻,现已将inode和dentry的结构体创立好,而且绑定好*/

filp = nameidata_to_filp(&nd, open_flag);

...................

}

static int do_path_lookup(int dfd, const char *name,

unsigned int flags, struct nameidata *nd)

{

...................

// 留意:这个函数才真实的分化途径,调用实践文件体系的操作。

林丹妻子// 它本身也是个简略封状,实践是运用 __link_p凯夫拉尔ath_walk() 函女尿尿数

// 完结操作。

retval = path_walk(name, nd);

...................

}

//分装的一个途径查找途径

static int path_walk(const char *name, struct nameidata *nd)

{

current->total_link_count = 0;

return link_path_walk(name, nd);

}

static __always_inline int link_path陈鲲羽家庭_walk(const char *name, struct nameidata *nd)

{

/驴马交配/对途径姓名进行解析权财,98,加勒比海盗4-雷竞技手机版_雷竞技手机版下载

result = __link_path_walk(name, nd);

}

static int __link_path_walk(const char *name, struct nameidata *nd)

{

//对途径的名name进行逐个剖分出一个dentry项,剖析完途径名之后再进行查找inode

..............................

// 从缓存或调用实践文件体系函数获取 inode 信息

到这儿才是查找对应 struct dentry 的详细操作,此函数首要从缓存中测验获取

struct dentry 结构。假如获取失利,则调用 real_lookup() 函数运用实践文件

体系办法来读取 inode 信息。这儿要清晰 struct dentry 中包含了 struct inode

信息。*/

//真实的开端查找了,do_lookup(),首要现在内存中的杂凑表中查找,假如没有找到

//那么就要到磁盘或许相应的块设备中去查找,并在内存树立相应的数据结构

//next是struct path类型的结构体,界说于/linux/fs/namei.c,用于保存从磁盘或许其他块设备上查找的信息

err = do_lookup(nd, &this, &next);

.....................................

}

static int do_lookup(struct nameidata *nd, struct qstr *name,

struct path *path)

{

struct vfsmount *mnt = nd->path.mnt;

// 从 hlist 中获取 struct dentry 结构,hlist 代表的是

// 一个 inode 的缓存便是一个 HASH 表

struct dentry *dentry = __d_lookup(nd->path.dentry, name);

//在缓冲区中没有找到指定姓名的dentry,调用real_lookup在磁盘中查找

/* 到这儿才是查找对应 struct dentry 的详细操作,此函数首要从缓存中测验获取

struct dentry 结构。假如获取失利,则调用 real_lookup() 函数运用实践文件

体系办法来读取 inode 信息。这儿要清晰 struct dentry 中包含了 struct inode

信息。 */

// 假如没有找到则会调用 real_lookup() 实践文件体系办法

// 从磁盘中获取

if (!dent权财,98,加勒比海盗4-雷竞技手机版_雷竞技手机版下载ry)

goto need_lookup;

if (dentry->d_op && dentry->d_op->d_revalidate)

goto need_revalidate;

done:// 假如从缓存中找到,则设置 struct path 并回来

path->mnt = mnt;

path->dentry = dentry;

__follow_mount(path);

return 0;

need_lookup:

// 从磁盘中获取// 运用实践文件体系办法,从磁盘中取得 inode 信息

dentry = real_lookup(nd->path.dentry, name, nd);

.........................

}

//当一切查找dentry的办法都失效的时分,只要调用real_lookup()到磁盘中查找inode

static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, struct nameidata *nd)

{

/*

在剖析 real_lookup() 函数前,咱们先来看一下 ext3 文件体系的 inode

结构。很明显能够看出 lookup 指向了 ext3_lookup() 函数。

存放在 /fs/ext3/namei.c

struct inode_operations ext3_dir_inode_operations = {

......

.lookup = ext3_lookup,

......

};

file_system_type

register_filesystem

vfs_kern_mount

此初中女生的胸部函数先从缓存中查找对应的 inode,假如没有则新分配一个 struct dentry

结构,然后调用 parent->d_inode->i_op->lookup 即调用了 ext3_lookup()

函数来查找 inode。

Lookup函数还会调用到一个重要的函数inode = ext3_iget(dir->i_sb, ino);

*/

result = dir->i_op->lookup(dir, dentry, nd);

}

//Lookup函数还会调用到一个重要的函数inode = ext3_iget(dir->i_sb, ino);该函数比较复杂,首要是完结inode的赋值,然后依据inode的信息来判别该文件究竟是什么类型的文件,然后会调用究竟层向对应的操作该文件的办法对其进行操作

struct inode *ext3_iget(struct super_block *sb, unsigned long ino)

{

// 留意:这儿的 __ext3_get_inode_loc 是发生

// 一个磁盘 I/O 从磁盘读取真实的 struct inode

// 来填充 in core 类型的。留意这个函数运用的

// 第三个参数,为 0 的状况下发生 I/O 从磁盘

// 读取,否则从 buffer_head 磁盘缓存中查找。

ret = __ext3_get_inode_loc(inode, &iloc, 0);

// 假如是一般文件的话,则运用 ext3_file_xxx 函数集

// 留意:在运用 ext3_file_operations 函数集时,它的

// open 函数对应的是 generic_file_open() 函权财,98,加勒比海盗4-雷竞技手机版_雷竞技手机版下载数,而这个函数

// 除了判别大文件是否合法外,简直便是一个空函数,也便是说

// 假如是在一个 ext3 文件体系上,open 操作其实没有任何详细

// 动作,是无意义的。为什么会这样呢?在后面介绍文件体系时

// 会讲到。

if (S_ISREG(inode->i_mode)) {//是一般文件,运用一般文件的操作办法

inode->i_op = &ext3_file_inode_operations;

inode->i_fop = &ext3_file_operations;

ext3_set_aops(inode);

} else if (S_ISDIR(inode->i_mode)) {// 假如是目录的话,则要区别对待,运用 ext3_dir_xxx 函数集

inode->i_op = &ext3_dir_inode_operations;

in管家拐到床上来ode->i_fop = &ext3_dir_operations;

} else if (S_ISLNK(inode->i_mode)) {

if (ext3_inode_is_fast_symlink(inode)) {// 假如是衔接的话,也要区别对待,运用 ext3_symlink_xxx 函数集

inode->i_op = &ext3_fast_symlink_inode_operations;

nd_terminate_link(ei->i_data, inode->i_size,

sizeof(ei->i_data) - 1);

} else {

inode->i_op = &ext3_symlink_inode_operations;

ext3_set_aops(inode);

}

} else {

// 假如以上三种状况都排除了,那么咱们则以为他是一个设备驱动

// 留意:这儿的仅对 inode->i_op 函数集进行了直接赋值。关于

// inode->i_fop 函数集运用的是 init_special_inode() 函数

// 进行的赋值

inode->i_op = &ext3_special_inode_operations;//对inode的操作办法进行赋值

if (raw_inode->i_block[0])

init_special_inode(inode, inode->i_mode,//运用init_special_inode() 对文件操作办法进行进行赋值

old_decode_dev(le32_to_cpu(raw_inode->i_block[权财,98,加勒比海盗4-雷竞技手机版_雷竞技手机版下载0])));

else

//例如是字符设备,在此处依据inode的信息,找到struct cdev对应的是咱们自己完结的字符设备驱动

//在此处会将咱们完结的字符设备驱动操作办法,赋值给文件结构体的操作办法。

init_special_inode(inode, inode->i_mode,

new_decode_de权财,98,加勒比海盗4-雷竞技手机版_雷竞技手机版下载v(le32_to_cpu(raw_inode->i_block[1])));

}

}

函数void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev)中又会对inode所对应的设备类型进行一个进一步的剖析,然后运用到相对应不同的设备的操作办法进行操作。

void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev)

{

inode->i_mode = mode;

if (S_ISCHR(mode)) {//字符设备

inode->i_fop = &def_chr_fops;

inode->i_rdev = rdev;

} else if (S_ISBLK(mode)) {//块设备

inode->i_fop = &def_blk_fo权财,98,加勒比海盗4-雷竞技手机版_雷竞技手机版下载ps;

inode->i_rdev = rdev;

} else if (S_ISFIFO(mode))//FIFO设备

inode->i_fop = &def_fifo_fops;

else if (S_ISSOCK(mode))//网络设备

inode->i_fop = &bad_sock_fops;

else

printk(KERN_DEBUG "init_special_inode: bogus i_mode (%o)\n",

mode);

}

/*

这个函数依据 struct namei乌兰巴托不眠夜data 结构回来一个 struct file。能够看到

struct file 是在运用了 __dentry_open() 函数后被填充的,且运用的第

一个参数是 nameidata->dentry,这也是为什么咱们要取得 struct nameidata

的一个首要原因,其意图便是为了得到 struct dentry 结构。

在此刻,现已将inode和dentry的结构体创立好,而且绑定好,关于不同类型的设备

在上一步现已将其对应的默许文件操作办法赋值*/

struct file *nameidata_to_filp(struct nameidata *nd, int flags)

{

struct file *filp;

/* Pick up the filp from the open intent */

filp = nd->intent.open.file;

/* Has the filesystem initialised the file for us? */

if (filp->f_path.dentry == NULL)

// 这个函数首要便是填充一个 struct file 结构,经过这段

// 代码也能够看到,一个 struct file 是动态分配的。

filp = __dentry_open(n普鲁狮指纹锁d->path.dentry, nd->path.mnt, flags, filp,

NULL, cred);

return filp;

}

static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,

int flags, struct file *f,

int (*open)(struct inode *, struct file *),

const struct cred *cred)

{

f->f_op = fops_get(inode->i_fop);

file_move(f, &inode->i_sb->s_files);

if (!open && f->f_op)

open = f->f_op->open;// 此处调用 def_chr_fops里的open函数,即chrdev_open

if (open) {

error = openfakeagent(inode, f);

if (e权财,98,加勒比海盗4-雷竞技手机版_雷竞技手机版下载rror)

goto clea武侠国际直播体系nup_all;

}

}

咱们重视哦

linux

热门
最新
推荐
标签